You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gi...@apache.org on 2026/02/26 14:52:31 UTC
(hbase-site) branch asf-site updated: Published site at 01f93dbf6add6223851a0482842f4253e53b966f.
This is an automated email from the ASF dual-hosted git repository.
git-site-role pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/hbase-site.git
The following commit(s) were added to refs/heads/asf-site by this push:
new da5b562cf34 Published site at 01f93dbf6add6223851a0482842f4253e53b966f.
da5b562cf34 is described below
commit da5b562cf34ee7434b9fcc5072600f6297fd68eb
Author: jenkins <bu...@apache.org>
AuthorDate: Thu Feb 26 14:52:22 2026 +0000
Published site at 01f93dbf6add6223851a0482842f4253e53b966f.
---
apache_hbase_reference_guide.pdf | 4 +-
.../hadoop/hbase/regionserver/StoreScanner.html | 726 ++++++++++-----------
book.html | 2 +-
checkstyle-aggregate.html | 8 +-
dependency-convergence.html | 2 +-
dependency-info.html | 2 +-
dependency-management.html | 2 +-
.../hadoop/hbase/regionserver/StoreScanner.html | 44 +-
.../hadoop/hbase/regionserver/StoreScanner.html | 726 ++++++++++-----------
hbase-website/dependency-convergence.html | 2 +-
hbase-website/dependency-info.html | 2 +-
hbase-website/dependency-management.html | 2 +-
hbase-website/index.html | 2 +-
hbase-website/issue-management.html | 2 +-
hbase-website/licenses.html | 2 +-
hbase-website/mailing-lists.html | 2 +-
hbase-website/plugin-management.html | 2 +-
hbase-website/plugins.html | 2 +-
hbase-website/project-info.html | 2 +-
hbase-website/scm.html | 2 +-
hbase-website/summary.html | 2 +-
hbase-website/team.html | 2 +-
issue-management.html | 2 +-
licenses.html | 2 +-
mailing-lists.html | 2 +-
plugin-management.html | 2 +-
plugins.html | 2 +-
project-info.html | 2 +-
project-reports.html | 2 +-
scm.html | 2 +-
summary.html | 2 +-
team.html | 2 +-
32 files changed, 779 insertions(+), 783 deletions(-)
diff --git a/apache_hbase_reference_guide.pdf b/apache_hbase_reference_guide.pdf
index 03bff025a2a..517746989b3 100644
--- a/apache_hbase_reference_guide.pdf
+++ b/apache_hbase_reference_guide.pdf
@@ -5,8 +5,8 @@
/Author (Apache HBase Team)
/Creator (Asciidoctor PDF 2.0.6, based on Prawn 2.4.0)
/Producer (Apache HBase Team)
-/ModDate (D:20260225143129+00'00')
-/CreationDate (D:20260225144748+00'00')
+/ModDate (D:20260226143122+00'00')
+/CreationDate (D:20260226144709+00'00')
>>
endobj
2 0 obj
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html b/apidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
index 4bcf5fa6220..3c845fd720d 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
@@ -977,370 +977,368 @@
<span class="source-line-no">964</span><span id="line-964"> } while ((nextCell = this.heap.peek()) != null && CellUtil.matchingRowColumn(cell, nextCell));</span>
<span class="source-line-no">965</span><span id="line-965"> // We need this check because it may happen that the new scanner that we get</span>
<span class="source-line-no">966</span><span id="line-966"> // during heap.next() is requiring reseek due of fake KV previously generated for</span>
-<span class="source-line-no">967</span><span id="line-967"> // ROWCOL bloom filter optimization. See HBASE-19863 for more details</span>
-<span class="source-line-no">968</span><span id="line-968"> if (</span>
-<span class="source-line-no">969</span><span id="line-969"> useRowColBloom && nextCell != null && cell.getTimestamp() == PrivateConstants.OLDEST_TIMESTAMP</span>
-<span class="source-line-no">970</span><span id="line-970"> ) {</span>
-<span class="source-line-no">971</span><span id="line-971"> return false;</span>
-<span class="source-line-no">972</span><span id="line-972"> }</span>
-<span class="source-line-no">973</span><span id="line-973"> return true;</span>
-<span class="source-line-no">974</span><span id="line-974"> }</span>
-<span class="source-line-no">975</span><span id="line-975"></span>
-<span class="source-line-no">976</span><span id="line-976"> @Override</span>
-<span class="source-line-no">977</span><span id="line-977"> public long getReadPoint() {</span>
-<span class="source-line-no">978</span><span id="line-978"> return this.readPt;</span>
-<span class="source-line-no">979</span><span id="line-979"> }</span>
-<span class="source-line-no">980</span><span id="line-980"></span>
-<span class="source-line-no">981</span><span id="line-981"> private static void clearAndClose(List<KeyValueScanner> scanners) {</span>
-<span class="source-line-no">982</span><span id="line-982"> if (scanners == null) {</span>
-<span class="source-line-no">983</span><span id="line-983"> return;</span>
-<span class="source-line-no">984</span><span id="line-984"> }</span>
-<span class="source-line-no">985</span><span id="line-985"> for (KeyValueScanner s : scanners) {</span>
-<span class="source-line-no">986</span><span id="line-986"> s.close();</span>
-<span class="source-line-no">987</span><span id="line-987"> }</span>
-<span class="source-line-no">988</span><span id="line-988"> scanners.clear();</span>
-<span class="source-line-no">989</span><span id="line-989"> }</span>
-<span class="source-line-no">990</span><span id="line-990"></span>
-<span class="source-line-no">991</span><span id="line-991"> // Implementation of ChangedReadersObserver</span>
-<span class="source-line-no">992</span><span id="line-992"> @Override</span>
-<span class="source-line-no">993</span><span id="line-993"> public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreScanners)</span>
-<span class="source-line-no">994</span><span id="line-994"> throws IOException {</span>
-<span class="source-line-no">995</span><span id="line-995"> if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {</span>
-<span class="source-line-no">996</span><span id="line-996"> return;</span>
-<span class="source-line-no">997</span><span id="line-997"> }</span>
-<span class="source-line-no">998</span><span id="line-998"> boolean updateReaders = false;</span>
-<span class="source-line-no">999</span><span id="line-999"> flushLock.lock();</span>
-<span class="source-line-no">1000</span><span id="line-1000"> try {</span>
-<span class="source-line-no">1001</span><span id="line-1001"> if (!closeLock.tryLock()) {</span>
-<span class="source-line-no">1002</span><span id="line-1002"> // The reason for doing this is that when the current store scanner does not retrieve</span>
-<span class="source-line-no">1003</span><span id="line-1003"> // any new cells, then the scanner is considered to be done. The heap of this scanner</span>
-<span class="source-line-no">1004</span><span id="line-1004"> // is not closed till the shipped() call is completed. Hence in that case if at all</span>
-<span class="source-line-no">1005</span><span id="line-1005"> // the partial close (close (false)) has been called before updateReaders(), there is no</span>
-<span class="source-line-no">1006</span><span id="line-1006"> // need for the updateReaders() to happen.</span>
-<span class="source-line-no">1007</span><span id="line-1007"> LOG.debug("StoreScanner already has the close lock. There is no need to updateReaders");</span>
-<span class="source-line-no">1008</span><span id="line-1008"> // no lock acquired.</span>
-<span class="source-line-no">1009</span><span id="line-1009"> clearAndClose(memStoreScanners);</span>
-<span class="source-line-no">1010</span><span id="line-1010"> return;</span>
-<span class="source-line-no">1011</span><span id="line-1011"> }</span>
-<span class="source-line-no">1012</span><span id="line-1012"> // lock acquired</span>
-<span class="source-line-no">1013</span><span id="line-1013"> updateReaders = true;</span>
-<span class="source-line-no">1014</span><span id="line-1014"> if (this.closing) {</span>
-<span class="source-line-no">1015</span><span id="line-1015"> LOG.debug("StoreScanner already closing. There is no need to updateReaders");</span>
-<span class="source-line-no">1016</span><span id="line-1016"> clearAndClose(memStoreScanners);</span>
-<span class="source-line-no">1017</span><span id="line-1017"> return;</span>
-<span class="source-line-no">1018</span><span id="line-1018"> }</span>
-<span class="source-line-no">1019</span><span id="line-1019"> flushed = true;</span>
-<span class="source-line-no">1020</span><span id="line-1020"> final boolean isCompaction = false;</span>
-<span class="source-line-no">1021</span><span id="line-1021"> boolean usePread = get || scanUsePread;</span>
-<span class="source-line-no">1022</span><span id="line-1022"> // SEE HBASE-19468 where the flushed files are getting compacted even before a scanner</span>
-<span class="source-line-no">1023</span><span id="line-1023"> // calls next(). So its better we create scanners here rather than next() call. Ensure</span>
-<span class="source-line-no">1024</span><span id="line-1024"> // these scanners are properly closed() whether or not the scan is completed successfully</span>
-<span class="source-line-no">1025</span><span id="line-1025"> // Eagerly creating scanners so that we have the ref counting ticking on the newly created</span>
-<span class="source-line-no">1026</span><span id="line-1026"> // store files. In case of stream scanners this eager creation does not induce performance</span>
-<span class="source-line-no">1027</span><span id="line-1027"> // penalty because in scans (that uses stream scanners) the next() call is bound to happen.</span>
-<span class="source-line-no">1028</span><span id="line-1028"> List<KeyValueScanner> scanners =</span>
-<span class="source-line-no">1029</span><span id="line-1029"> store.getScanners(sfs, cacheBlocks, get, usePread, isCompaction, matcher,</span>
-<span class="source-line-no">1030</span><span id="line-1030"> scan.getStartRow(), scan.getStopRow(), this.readPt, false, isOnlyLatestVersionScan(scan));</span>
-<span class="source-line-no">1031</span><span id="line-1031"> flushedstoreFileScanners.addAll(scanners);</span>
-<span class="source-line-no">1032</span><span id="line-1032"> if (!CollectionUtils.isEmpty(memStoreScanners)) {</span>
-<span class="source-line-no">1033</span><span id="line-1033"> clearAndClose(memStoreScannersAfterFlush);</span>
-<span class="source-line-no">1034</span><span id="line-1034"> memStoreScannersAfterFlush.addAll(memStoreScanners);</span>
-<span class="source-line-no">1035</span><span id="line-1035"> }</span>
-<span class="source-line-no">1036</span><span id="line-1036"> } finally {</span>
-<span class="source-line-no">1037</span><span id="line-1037"> flushLock.unlock();</span>
-<span class="source-line-no">1038</span><span id="line-1038"> if (updateReaders) {</span>
-<span class="source-line-no">1039</span><span id="line-1039"> closeLock.unlock();</span>
-<span class="source-line-no">1040</span><span id="line-1040"> }</span>
-<span class="source-line-no">1041</span><span id="line-1041"> if (hasUpdatedReaders != null) {</span>
-<span class="source-line-no">1042</span><span id="line-1042"> hasUpdatedReaders.set(true);</span>
-<span class="source-line-no">1043</span><span id="line-1043"> }</span>
-<span class="source-line-no">1044</span><span id="line-1044"> }</span>
-<span class="source-line-no">1045</span><span id="line-1045"> // Let the next() call handle re-creating and seeking</span>
-<span class="source-line-no">1046</span><span id="line-1046"> }</span>
-<span class="source-line-no">1047</span><span id="line-1047"></span>
-<span class="source-line-no">1048</span><span id="line-1048"> /** Returns if top of heap has changed (and KeyValueHeap has to try the next KV) */</span>
-<span class="source-line-no">1049</span><span id="line-1049"> protected final boolean reopenAfterFlush() throws IOException {</span>
-<span class="source-line-no">1050</span><span id="line-1050"> // here we can make sure that we have a Store instance so no null check on store.</span>
-<span class="source-line-no">1051</span><span id="line-1051"> ExtendedCell lastTop = heap.peek();</span>
-<span class="source-line-no">1052</span><span id="line-1052"> // When we have the scan object, should we not pass it to getScanners() to get a limited set of</span>
-<span class="source-line-no">1053</span><span id="line-1053"> // scanners? We did so in the constructor and we could have done it now by storing the scan</span>
-<span class="source-line-no">1054</span><span id="line-1054"> // object from the constructor</span>
-<span class="source-line-no">1055</span><span id="line-1055"> List<KeyValueScanner> scanners;</span>
-<span class="source-line-no">1056</span><span id="line-1056"> flushLock.lock();</span>
-<span class="source-line-no">1057</span><span id="line-1057"> try {</span>
-<span class="source-line-no">1058</span><span id="line-1058"> List<KeyValueScanner> allScanners =</span>
-<span class="source-line-no">1059</span><span id="line-1059"> new ArrayList<>(flushedstoreFileScanners.size() + memStoreScannersAfterFlush.size());</span>
-<span class="source-line-no">1060</span><span id="line-1060"> allScanners.addAll(flushedstoreFileScanners);</span>
-<span class="source-line-no">1061</span><span id="line-1061"> allScanners.addAll(memStoreScannersAfterFlush);</span>
-<span class="source-line-no">1062</span><span id="line-1062"> scanners = selectScannersFrom(store, allScanners);</span>
-<span class="source-line-no">1063</span><span id="line-1063"> // Clear the current set of flushed store files scanners so that they don't get added again</span>
-<span class="source-line-no">1064</span><span id="line-1064"> flushedstoreFileScanners.clear();</span>
-<span class="source-line-no">1065</span><span id="line-1065"> memStoreScannersAfterFlush.clear();</span>
-<span class="source-line-no">1066</span><span id="line-1066"> } finally {</span>
-<span class="source-line-no">1067</span><span id="line-1067"> flushLock.unlock();</span>
-<span class="source-line-no">1068</span><span id="line-1068"> }</span>
-<span class="source-line-no">1069</span><span id="line-1069"></span>
-<span class="source-line-no">1070</span><span id="line-1070"> // Seek the new scanners to the last key</span>
-<span class="source-line-no">1071</span><span id="line-1071"> seekScanners(scanners, lastTop, false, parallelSeekEnabled);</span>
-<span class="source-line-no">1072</span><span id="line-1072"> // remove the older memstore scanner</span>
-<span class="source-line-no">1073</span><span id="line-1073"> for (int i = currentScanners.size() - 1; i >= 0; i--) {</span>
-<span class="source-line-no">1074</span><span id="line-1074"> if (!currentScanners.get(i).isFileScanner()) {</span>
-<span class="source-line-no">1075</span><span id="line-1075"> scannersForDelayedClose.add(currentScanners.remove(i));</span>
-<span class="source-line-no">1076</span><span id="line-1076"> } else {</span>
-<span class="source-line-no">1077</span><span id="line-1077"> // we add the memstore scanner to the end of currentScanners</span>
-<span class="source-line-no">1078</span><span id="line-1078"> break;</span>
-<span class="source-line-no">1079</span><span id="line-1079"> }</span>
-<span class="source-line-no">1080</span><span id="line-1080"> }</span>
-<span class="source-line-no">1081</span><span id="line-1081"> // add the newly created scanners on the flushed files and the current active memstore scanner</span>
-<span class="source-line-no">1082</span><span id="line-1082"> addCurrentScanners(scanners);</span>
-<span class="source-line-no">1083</span><span id="line-1083"> // Combine all seeked scanners with a heap</span>
-<span class="source-line-no">1084</span><span id="line-1084"> resetKVHeap(this.currentScanners, store.getComparator());</span>
-<span class="source-line-no">1085</span><span id="line-1085"> resetQueryMatcher(lastTop);</span>
-<span class="source-line-no">1086</span><span id="line-1086"> if (heap.peek() == null || store.getComparator().compareRows(lastTop, this.heap.peek()) != 0) {</span>
-<span class="source-line-no">1087</span><span id="line-1087"> LOG.info("Storescanner.peek() is changed where before = " + lastTop.toString()</span>
-<span class="source-line-no">1088</span><span id="line-1088"> + ",and after = " + heap.peek());</span>
-<span class="source-line-no">1089</span><span id="line-1089"> topChanged = true;</span>
-<span class="source-line-no">1090</span><span id="line-1090"> } else {</span>
-<span class="source-line-no">1091</span><span id="line-1091"> topChanged = false;</span>
-<span class="source-line-no">1092</span><span id="line-1092"> }</span>
-<span class="source-line-no">1093</span><span id="line-1093"> return topChanged;</span>
-<span class="source-line-no">1094</span><span id="line-1094"> }</span>
-<span class="source-line-no">1095</span><span id="line-1095"></span>
-<span class="source-line-no">1096</span><span id="line-1096"> private void resetQueryMatcher(ExtendedCell lastTopKey) {</span>
-<span class="source-line-no">1097</span><span id="line-1097"> // Reset the state of the Query Matcher and set to top row.</span>
-<span class="source-line-no">1098</span><span id="line-1098"> // Only reset and call setRow if the row changes; avoids confusing the</span>
-<span class="source-line-no">1099</span><span id="line-1099"> // query matcher if scanning intra-row.</span>
-<span class="source-line-no">1100</span><span id="line-1100"> ExtendedCell cell = heap.peek();</span>
-<span class="source-line-no">1101</span><span id="line-1101"> if (cell == null) {</span>
-<span class="source-line-no">1102</span><span id="line-1102"> cell = lastTopKey;</span>
-<span class="source-line-no">1103</span><span id="line-1103"> }</span>
-<span class="source-line-no">1104</span><span id="line-1104"> if ((matcher.currentRow() == null) || !CellUtil.matchingRows(cell, matcher.currentRow())) {</span>
-<span class="source-line-no">1105</span><span id="line-1105"> this.countPerRow = 0;</span>
-<span class="source-line-no">1106</span><span id="line-1106"> // The setToNewRow will call reset internally</span>
-<span class="source-line-no">1107</span><span id="line-1107"> matcher.setToNewRow(cell);</span>
-<span class="source-line-no">1108</span><span id="line-1108"> }</span>
-<span class="source-line-no">1109</span><span id="line-1109"> }</span>
-<span class="source-line-no">1110</span><span id="line-1110"></span>
-<span class="source-line-no">1111</span><span id="line-1111"> /**</span>
-<span class="source-line-no">1112</span><span id="line-1112"> * Check whether scan as expected order</span>
-<span class="source-line-no">1113</span><span id="line-1113"> */</span>
-<span class="source-line-no">1114</span><span id="line-1114"> protected void checkScanOrder(Cell prevKV, Cell kv, CellComparator comparator)</span>
-<span class="source-line-no">1115</span><span id="line-1115"> throws IOException {</span>
-<span class="source-line-no">1116</span><span id="line-1116"> // Check that the heap gives us KVs in an increasing order.</span>
-<span class="source-line-no">1117</span><span id="line-1117"> assert prevKV == null || comparator == null || comparator.compare(prevKV, kv) <= 0</span>
-<span class="source-line-no">1118</span><span id="line-1118"> : "Key " + prevKV + " followed by a smaller key " + kv + " in cf " + store;</span>
-<span class="source-line-no">1119</span><span id="line-1119"> }</span>
-<span class="source-line-no">1120</span><span id="line-1120"></span>
-<span class="source-line-no">1121</span><span id="line-1121"> protected boolean seekToNextRow(ExtendedCell c) throws IOException {</span>
-<span class="source-line-no">1122</span><span id="line-1122"> return reseek(PrivateCellUtil.createLastOnRow(c));</span>
-<span class="source-line-no">1123</span><span id="line-1123"> }</span>
-<span class="source-line-no">1124</span><span id="line-1124"></span>
-<span class="source-line-no">1125</span><span id="line-1125"> /**</span>
-<span class="source-line-no">1126</span><span id="line-1126"> * Do a reseek in a normal StoreScanner(scan forward)</span>
-<span class="source-line-no">1127</span><span id="line-1127"> * @return true if scanner has values left, false if end of scanner</span>
-<span class="source-line-no">1128</span><span id="line-1128"> */</span>
-<span class="source-line-no">1129</span><span id="line-1129"> protected boolean seekAsDirection(ExtendedCell kv) throws IOException {</span>
-<span class="source-line-no">1130</span><span id="line-1130"> return reseek(kv);</span>
-<span class="source-line-no">1131</span><span id="line-1131"> }</span>
-<span class="source-line-no">1132</span><span id="line-1132"></span>
-<span class="source-line-no">1133</span><span id="line-1133"> @Override</span>
-<span class="source-line-no">1134</span><span id="line-1134"> public boolean reseek(ExtendedCell kv) throws IOException {</span>
-<span class="source-line-no">1135</span><span id="line-1135"> if (checkFlushed()) {</span>
-<span class="source-line-no">1136</span><span id="line-1136"> reopenAfterFlush();</span>
-<span class="source-line-no">1137</span><span id="line-1137"> }</span>
-<span class="source-line-no">1138</span><span id="line-1138"> if (explicitColumnQuery && lazySeekEnabledGlobally) {</span>
-<span class="source-line-no">1139</span><span id="line-1139"> return heap.requestSeek(kv, true, useRowColBloom);</span>
-<span class="source-line-no">1140</span><span id="line-1140"> }</span>
-<span class="source-line-no">1141</span><span id="line-1141"> return heap.reseek(kv);</span>
-<span class="source-line-no">1142</span><span id="line-1142"> }</span>
-<span class="source-line-no">1143</span><span id="line-1143"></span>
-<span class="source-line-no">1144</span><span id="line-1144"> void trySwitchToStreamRead() {</span>
-<span class="source-line-no">1145</span><span id="line-1145"> if (</span>
-<span class="source-line-no">1146</span><span id="line-1146"> readType != Scan.ReadType.DEFAULT || !scanUsePread || closing || heap.peek() == null</span>
-<span class="source-line-no">1147</span><span id="line-1147"> || bytesRead < preadMaxBytes</span>
-<span class="source-line-no">1148</span><span id="line-1148"> ) {</span>
-<span class="source-line-no">1149</span><span id="line-1149"> return;</span>
-<span class="source-line-no">1150</span><span id="line-1150"> }</span>
-<span class="source-line-no">1151</span><span id="line-1151"> LOG.debug("Switch to stream read (scanned={} bytes) of {}", bytesRead,</span>
-<span class="source-line-no">1152</span><span id="line-1152"> this.store.getColumnFamilyName());</span>
-<span class="source-line-no">1153</span><span id="line-1153"> scanUsePread = false;</span>
-<span class="source-line-no">1154</span><span id="line-1154"> ExtendedCell lastTop = heap.peek();</span>
-<span class="source-line-no">1155</span><span id="line-1155"> List<KeyValueScanner> memstoreScanners = new ArrayList<>();</span>
-<span class="source-line-no">1156</span><span id="line-1156"> List<KeyValueScanner> scannersToClose = new ArrayList<>();</span>
-<span class="source-line-no">1157</span><span id="line-1157"> for (KeyValueScanner kvs : currentScanners) {</span>
-<span class="source-line-no">1158</span><span id="line-1158"> if (!kvs.isFileScanner()) {</span>
-<span class="source-line-no">1159</span><span id="line-1159"> // collect memstorescanners here</span>
-<span class="source-line-no">1160</span><span id="line-1160"> memstoreScanners.add(kvs);</span>
-<span class="source-line-no">1161</span><span id="line-1161"> } else {</span>
-<span class="source-line-no">1162</span><span id="line-1162"> scannersToClose.add(kvs);</span>
-<span class="source-line-no">1163</span><span id="line-1163"> }</span>
-<span class="source-line-no">1164</span><span id="line-1164"> }</span>
-<span class="source-line-no">1165</span><span id="line-1165"> List<KeyValueScanner> fileScanners = null;</span>
-<span class="source-line-no">1166</span><span id="line-1166"> List<KeyValueScanner> newCurrentScanners;</span>
-<span class="source-line-no">1167</span><span id="line-1167"> KeyValueHeap newHeap;</span>
-<span class="source-line-no">1168</span><span id="line-1168"> try {</span>
-<span class="source-line-no">1169</span><span id="line-1169"> // We must have a store instance here so no null check</span>
-<span class="source-line-no">1170</span><span id="line-1170"> // recreate the scanners on the current file scanners</span>
-<span class="source-line-no">1171</span><span id="line-1171"> fileScanners = store.recreateScanners(scannersToClose, cacheBlocks, false, false, matcher,</span>
-<span class="source-line-no">1172</span><span id="line-1172"> scan.getStartRow(), scan.includeStartRow(), scan.getStopRow(), scan.includeStopRow(),</span>
-<span class="source-line-no">1173</span><span id="line-1173"> readPt, false);</span>
-<span class="source-line-no">1174</span><span id="line-1174"> if (fileScanners == null) {</span>
-<span class="source-line-no">1175</span><span id="line-1175"> return;</span>
-<span class="source-line-no">1176</span><span id="line-1176"> }</span>
-<span class="source-line-no">1177</span><span id="line-1177"> seekScanners(fileScanners, lastTop, false, parallelSeekEnabled);</span>
-<span class="source-line-no">1178</span><span id="line-1178"> newCurrentScanners = new ArrayList<>(fileScanners.size() + memstoreScanners.size());</span>
-<span class="source-line-no">1179</span><span id="line-1179"> newCurrentScanners.addAll(fileScanners);</span>
-<span class="source-line-no">1180</span><span id="line-1180"> newCurrentScanners.addAll(memstoreScanners);</span>
-<span class="source-line-no">1181</span><span id="line-1181"> newHeap = newKVHeap(newCurrentScanners, comparator);</span>
-<span class="source-line-no">1182</span><span id="line-1182"> } catch (Exception e) {</span>
-<span class="source-line-no">1183</span><span id="line-1183"> LOG.warn("failed to switch to stream read", e);</span>
-<span class="source-line-no">1184</span><span id="line-1184"> if (fileScanners != null) {</span>
-<span class="source-line-no">1185</span><span id="line-1185"> fileScanners.forEach(KeyValueScanner::close);</span>
-<span class="source-line-no">1186</span><span id="line-1186"> }</span>
-<span class="source-line-no">1187</span><span id="line-1187"> return;</span>
-<span class="source-line-no">1188</span><span id="line-1188"> }</span>
-<span class="source-line-no">1189</span><span id="line-1189"> currentScanners.clear();</span>
-<span class="source-line-no">1190</span><span id="line-1190"> addCurrentScanners(newCurrentScanners);</span>
-<span class="source-line-no">1191</span><span id="line-1191"> this.heap = newHeap;</span>
-<span class="source-line-no">1192</span><span id="line-1192"> resetQueryMatcher(lastTop);</span>
-<span class="source-line-no">1193</span><span id="line-1193"> scannersToClose.forEach(KeyValueScanner::close);</span>
-<span class="source-line-no">1194</span><span id="line-1194"> if (hasSwitchedToStreamRead != null) {</span>
-<span class="source-line-no">1195</span><span id="line-1195"> hasSwitchedToStreamRead.set(true);</span>
-<span class="source-line-no">1196</span><span id="line-1196"> }</span>
-<span class="source-line-no">1197</span><span id="line-1197"> }</span>
-<span class="source-line-no">1198</span><span id="line-1198"></span>
-<span class="source-line-no">1199</span><span id="line-1199"> protected final boolean checkFlushed() {</span>
-<span class="source-line-no">1200</span><span id="line-1200"> // check the var without any lock. Suppose even if we see the old</span>
-<span class="source-line-no">1201</span><span id="line-1201"> // value here still it is ok to continue because we will not be resetting</span>
-<span class="source-line-no">1202</span><span id="line-1202"> // the heap but will continue with the referenced memstore's snapshot. For compactions</span>
-<span class="source-line-no">1203</span><span id="line-1203"> // any way we don't need the updateReaders at all to happen as we still continue with</span>
-<span class="source-line-no">1204</span><span id="line-1204"> // the older files</span>
-<span class="source-line-no">1205</span><span id="line-1205"> if (flushed) {</span>
-<span class="source-line-no">1206</span><span id="line-1206"> // If there is a flush and the current scan is notified on the flush ensure that the</span>
-<span class="source-line-no">1207</span><span id="line-1207"> // scan's heap gets reset and we do a seek on the newly flushed file.</span>
-<span class="source-line-no">1208</span><span id="line-1208"> if (this.closing) {</span>
-<span class="source-line-no">1209</span><span id="line-1209"> return false;</span>
-<span class="source-line-no">1210</span><span id="line-1210"> }</span>
-<span class="source-line-no">1211</span><span id="line-1211"> // reset the flag</span>
-<span class="source-line-no">1212</span><span id="line-1212"> flushed = false;</span>
-<span class="source-line-no">1213</span><span id="line-1213"> return true;</span>
-<span class="source-line-no">1214</span><span id="line-1214"> }</span>
-<span class="source-line-no">1215</span><span id="line-1215"> return false;</span>
-<span class="source-line-no">1216</span><span id="line-1216"> }</span>
-<span class="source-line-no">1217</span><span id="line-1217"></span>
-<span class="source-line-no">1218</span><span id="line-1218"> /**</span>
-<span class="source-line-no">1219</span><span id="line-1219"> * Seek storefiles in parallel to optimize IO latency as much as possible</span>
-<span class="source-line-no">1220</span><span id="line-1220"> * @param scanners the list {@link KeyValueScanner}s to be read from</span>
-<span class="source-line-no">1221</span><span id="line-1221"> * @param kv the KeyValue on which the operation is being requested</span>
-<span class="source-line-no">1222</span><span id="line-1222"> */</span>
-<span class="source-line-no">1223</span><span id="line-1223"> private void parallelSeek(final List<? extends KeyValueScanner> scanners, final ExtendedCell kv)</span>
-<span class="source-line-no">1224</span><span id="line-1224"> throws IOException {</span>
-<span class="source-line-no">1225</span><span id="line-1225"> if (scanners.isEmpty()) return;</span>
-<span class="source-line-no">1226</span><span id="line-1226"> int storeFileScannerCount = scanners.size();</span>
-<span class="source-line-no">1227</span><span id="line-1227"> CountDownLatch latch = new CountDownLatch(storeFileScannerCount);</span>
-<span class="source-line-no">1228</span><span id="line-1228"> List<ParallelSeekHandler> handlers = new ArrayList<>(storeFileScannerCount);</span>
-<span class="source-line-no">1229</span><span id="line-1229"> for (KeyValueScanner scanner : scanners) {</span>
-<span class="source-line-no">1230</span><span id="line-1230"> if (scanner instanceof StoreFileScanner) {</span>
-<span class="source-line-no">1231</span><span id="line-1231"> ParallelSeekHandler seekHandler = new ParallelSeekHandler(scanner, kv, this.readPt, latch);</span>
-<span class="source-line-no">1232</span><span id="line-1232"> executor.submit(seekHandler);</span>
-<span class="source-line-no">1233</span><span id="line-1233"> handlers.add(seekHandler);</span>
-<span class="source-line-no">1234</span><span id="line-1234"> } else {</span>
-<span class="source-line-no">1235</span><span id="line-1235"> scanner.seek(kv);</span>
-<span class="source-line-no">1236</span><span id="line-1236"> latch.countDown();</span>
-<span class="source-line-no">1237</span><span id="line-1237"> }</span>
-<span class="source-line-no">1238</span><span id="line-1238"> }</span>
-<span class="source-line-no">1239</span><span id="line-1239"></span>
-<span class="source-line-no">1240</span><span id="line-1240"> try {</span>
-<span class="source-line-no">1241</span><span id="line-1241"> latch.await();</span>
-<span class="source-line-no">1242</span><span id="line-1242"> } catch (InterruptedException ie) {</span>
-<span class="source-line-no">1243</span><span id="line-1243"> throw (InterruptedIOException) new InterruptedIOException().initCause(ie);</span>
-<span class="source-line-no">1244</span><span id="line-1244"> }</span>
-<span class="source-line-no">1245</span><span id="line-1245"></span>
-<span class="source-line-no">1246</span><span id="line-1246"> for (ParallelSeekHandler handler : handlers) {</span>
-<span class="source-line-no">1247</span><span id="line-1247"> if (handler.getErr() != null) {</span>
-<span class="source-line-no">1248</span><span id="line-1248"> throw new IOException(handler.getErr());</span>
-<span class="source-line-no">1249</span><span id="line-1249"> }</span>
-<span class="source-line-no">1250</span><span id="line-1250"> }</span>
-<span class="source-line-no">1251</span><span id="line-1251"> }</span>
-<span class="source-line-no">1252</span><span id="line-1252"></span>
-<span class="source-line-no">1253</span><span id="line-1253"> /**</span>
-<span class="source-line-no">1254</span><span id="line-1254"> * Used in testing.</span>
-<span class="source-line-no">1255</span><span id="line-1255"> * @return all scanners in no particular order</span>
-<span class="source-line-no">1256</span><span id="line-1256"> */</span>
-<span class="source-line-no">1257</span><span id="line-1257"> List<KeyValueScanner> getAllScannersForTesting() {</span>
-<span class="source-line-no">1258</span><span id="line-1258"> List<KeyValueScanner> allScanners = new ArrayList<>();</span>
-<span class="source-line-no">1259</span><span id="line-1259"> KeyValueScanner current = heap.getCurrentForTesting();</span>
-<span class="source-line-no">1260</span><span id="line-1260"> if (current != null) allScanners.add(current);</span>
-<span class="source-line-no">1261</span><span id="line-1261"> for (KeyValueScanner scanner : heap.getHeap())</span>
-<span class="source-line-no">1262</span><span id="line-1262"> allScanners.add(scanner);</span>
-<span class="source-line-no">1263</span><span id="line-1263"> return allScanners;</span>
-<span class="source-line-no">1264</span><span id="line-1264"> }</span>
-<span class="source-line-no">1265</span><span id="line-1265"></span>
-<span class="source-line-no">1266</span><span id="line-1266"> static void enableLazySeekGlobally(boolean enable) {</span>
-<span class="source-line-no">1267</span><span id="line-1267"> lazySeekEnabledGlobally = enable;</span>
-<span class="source-line-no">1268</span><span id="line-1268"> }</span>
-<span class="source-line-no">1269</span><span id="line-1269"></span>
-<span class="source-line-no">1270</span><span id="line-1270"> /** Returns The estimated number of KVs seen by this scanner (includes some skipped KVs). */</span>
-<span class="source-line-no">1271</span><span id="line-1271"> public long getEstimatedNumberOfKvsScanned() {</span>
-<span class="source-line-no">1272</span><span id="line-1272"> return this.kvsScanned;</span>
-<span class="source-line-no">1273</span><span id="line-1273"> }</span>
-<span class="source-line-no">1274</span><span id="line-1274"></span>
-<span class="source-line-no">1275</span><span id="line-1275"> @Override</span>
-<span class="source-line-no">1276</span><span id="line-1276"> public ExtendedCell getNextIndexedKey() {</span>
-<span class="source-line-no">1277</span><span id="line-1277"> return this.heap.getNextIndexedKey();</span>
-<span class="source-line-no">1278</span><span id="line-1278"> }</span>
-<span class="source-line-no">1279</span><span id="line-1279"></span>
-<span class="source-line-no">1280</span><span id="line-1280"> @Override</span>
-<span class="source-line-no">1281</span><span id="line-1281"> public void shipped() throws IOException {</span>
-<span class="source-line-no">1282</span><span id="line-1282"> if (prevCell != null) {</span>
-<span class="source-line-no">1283</span><span id="line-1283"> // Do the copy here so that in case the prevCell ref is pointing to the previous</span>
-<span class="source-line-no">1284</span><span id="line-1284"> // blocks we can safely release those blocks.</span>
-<span class="source-line-no">1285</span><span id="line-1285"> // This applies to blocks that are got from Bucket cache, L1 cache and the blocks</span>
-<span class="source-line-no">1286</span><span id="line-1286"> // fetched from HDFS. Copying this would ensure that we let go the references to these</span>
-<span class="source-line-no">1287</span><span id="line-1287"> // blocks so that they can be GCed safely(in case of bucket cache)</span>
-<span class="source-line-no">1288</span><span id="line-1288"> prevCell = KeyValueUtil.toNewKeyCell(this.prevCell);</span>
-<span class="source-line-no">1289</span><span id="line-1289"> }</span>
-<span class="source-line-no">1290</span><span id="line-1290"> matcher.beforeShipped();</span>
-<span class="source-line-no">1291</span><span id="line-1291"> // There wont be further fetch of Cells from these scanners. Just close.</span>
-<span class="source-line-no">1292</span><span id="line-1292"> clearAndClose(scannersForDelayedClose);</span>
-<span class="source-line-no">1293</span><span id="line-1293"> if (this.heap != null) {</span>
-<span class="source-line-no">1294</span><span id="line-1294"> this.heap.shipped();</span>
-<span class="source-line-no">1295</span><span id="line-1295"> // When switching from pread to stream, we will open a new scanner for each store file, but</span>
-<span class="source-line-no">1296</span><span id="line-1296"> // the old scanner may still track the HFileBlocks we have scanned but not sent back to client</span>
-<span class="source-line-no">1297</span><span id="line-1297"> // yet. If we close the scanner immediately then the HFileBlocks may be messed up by others</span>
-<span class="source-line-no">1298</span><span id="line-1298"> // before we serialize and send it back to client. The HFileBlocks will be released in shipped</span>
-<span class="source-line-no">1299</span><span id="line-1299"> // method, so we here will also open new scanners and close old scanners in shipped method.</span>
-<span class="source-line-no">1300</span><span id="line-1300"> // See HBASE-18055 for more details.</span>
-<span class="source-line-no">1301</span><span id="line-1301"> trySwitchToStreamRead();</span>
-<span class="source-line-no">1302</span><span id="line-1302"> }</span>
-<span class="source-line-no">1303</span><span id="line-1303"> }</span>
-<span class="source-line-no">1304</span><span id="line-1304"></span>
-<span class="source-line-no">1305</span><span id="line-1305"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1306</span><span id="line-1306"> static final void instrument() {</span>
-<span class="source-line-no">1307</span><span id="line-1307"> hasUpdatedReaders = new AtomicBoolean(false);</span>
-<span class="source-line-no">1308</span><span id="line-1308"> hasSwitchedToStreamRead = new AtomicBoolean(false);</span>
-<span class="source-line-no">1309</span><span id="line-1309"> }</span>
-<span class="source-line-no">1310</span><span id="line-1310"></span>
-<span class="source-line-no">1311</span><span id="line-1311"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1312</span><span id="line-1312"> static final boolean hasUpdatedReaders() {</span>
-<span class="source-line-no">1313</span><span id="line-1313"> return hasUpdatedReaders.get();</span>
-<span class="source-line-no">1314</span><span id="line-1314"> }</span>
-<span class="source-line-no">1315</span><span id="line-1315"></span>
-<span class="source-line-no">1316</span><span id="line-1316"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1317</span><span id="line-1317"> static final boolean hasSwitchedToStreamRead() {</span>
-<span class="source-line-no">1318</span><span id="line-1318"> return hasSwitchedToStreamRead.get();</span>
-<span class="source-line-no">1319</span><span id="line-1319"> }</span>
-<span class="source-line-no">1320</span><span id="line-1320"></span>
-<span class="source-line-no">1321</span><span id="line-1321"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1322</span><span id="line-1322"> static final void resetHasUpdatedReaders() {</span>
-<span class="source-line-no">1323</span><span id="line-1323"> hasUpdatedReaders.set(false);</span>
-<span class="source-line-no">1324</span><span id="line-1324"> }</span>
-<span class="source-line-no">1325</span><span id="line-1325"></span>
-<span class="source-line-no">1326</span><span id="line-1326"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1327</span><span id="line-1327"> static final void resetHasSwitchedToStreamRead() {</span>
-<span class="source-line-no">1328</span><span id="line-1328"> hasSwitchedToStreamRead.set(false);</span>
-<span class="source-line-no">1329</span><span id="line-1329"> }</span>
-<span class="source-line-no">1330</span><span id="line-1330">}</span>
+<span class="source-line-no">967</span><span id="line-967"> // ROWCOL bloom filter optimization. See HBASE-19863 and HBASE-29907 for more details</span>
+<span class="source-line-no">968</span><span id="line-968"> if (useRowColBloom && nextCell != null && matcher.compareKeyForNextColumn(nextCell, cell) < 0) {</span>
+<span class="source-line-no">969</span><span id="line-969"> return false;</span>
+<span class="source-line-no">970</span><span id="line-970"> }</span>
+<span class="source-line-no">971</span><span id="line-971"> return true;</span>
+<span class="source-line-no">972</span><span id="line-972"> }</span>
+<span class="source-line-no">973</span><span id="line-973"></span>
+<span class="source-line-no">974</span><span id="line-974"> @Override</span>
+<span class="source-line-no">975</span><span id="line-975"> public long getReadPoint() {</span>
+<span class="source-line-no">976</span><span id="line-976"> return this.readPt;</span>
+<span class="source-line-no">977</span><span id="line-977"> }</span>
+<span class="source-line-no">978</span><span id="line-978"></span>
+<span class="source-line-no">979</span><span id="line-979"> private static void clearAndClose(List<KeyValueScanner> scanners) {</span>
+<span class="source-line-no">980</span><span id="line-980"> if (scanners == null) {</span>
+<span class="source-line-no">981</span><span id="line-981"> return;</span>
+<span class="source-line-no">982</span><span id="line-982"> }</span>
+<span class="source-line-no">983</span><span id="line-983"> for (KeyValueScanner s : scanners) {</span>
+<span class="source-line-no">984</span><span id="line-984"> s.close();</span>
+<span class="source-line-no">985</span><span id="line-985"> }</span>
+<span class="source-line-no">986</span><span id="line-986"> scanners.clear();</span>
+<span class="source-line-no">987</span><span id="line-987"> }</span>
+<span class="source-line-no">988</span><span id="line-988"></span>
+<span class="source-line-no">989</span><span id="line-989"> // Implementation of ChangedReadersObserver</span>
+<span class="source-line-no">990</span><span id="line-990"> @Override</span>
+<span class="source-line-no">991</span><span id="line-991"> public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreScanners)</span>
+<span class="source-line-no">992</span><span id="line-992"> throws IOException {</span>
+<span class="source-line-no">993</span><span id="line-993"> if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {</span>
+<span class="source-line-no">994</span><span id="line-994"> return;</span>
+<span class="source-line-no">995</span><span id="line-995"> }</span>
+<span class="source-line-no">996</span><span id="line-996"> boolean updateReaders = false;</span>
+<span class="source-line-no">997</span><span id="line-997"> flushLock.lock();</span>
+<span class="source-line-no">998</span><span id="line-998"> try {</span>
+<span class="source-line-no">999</span><span id="line-999"> if (!closeLock.tryLock()) {</span>
+<span class="source-line-no">1000</span><span id="line-1000"> // The reason for doing this is that when the current store scanner does not retrieve</span>
+<span class="source-line-no">1001</span><span id="line-1001"> // any new cells, then the scanner is considered to be done. The heap of this scanner</span>
+<span class="source-line-no">1002</span><span id="line-1002"> // is not closed till the shipped() call is completed. Hence in that case if at all</span>
+<span class="source-line-no">1003</span><span id="line-1003"> // the partial close (close (false)) has been called before updateReaders(), there is no</span>
+<span class="source-line-no">1004</span><span id="line-1004"> // need for the updateReaders() to happen.</span>
+<span class="source-line-no">1005</span><span id="line-1005"> LOG.debug("StoreScanner already has the close lock. There is no need to updateReaders");</span>
+<span class="source-line-no">1006</span><span id="line-1006"> // no lock acquired.</span>
+<span class="source-line-no">1007</span><span id="line-1007"> clearAndClose(memStoreScanners);</span>
+<span class="source-line-no">1008</span><span id="line-1008"> return;</span>
+<span class="source-line-no">1009</span><span id="line-1009"> }</span>
+<span class="source-line-no">1010</span><span id="line-1010"> // lock acquired</span>
+<span class="source-line-no">1011</span><span id="line-1011"> updateReaders = true;</span>
+<span class="source-line-no">1012</span><span id="line-1012"> if (this.closing) {</span>
+<span class="source-line-no">1013</span><span id="line-1013"> LOG.debug("StoreScanner already closing. There is no need to updateReaders");</span>
+<span class="source-line-no">1014</span><span id="line-1014"> clearAndClose(memStoreScanners);</span>
+<span class="source-line-no">1015</span><span id="line-1015"> return;</span>
+<span class="source-line-no">1016</span><span id="line-1016"> }</span>
+<span class="source-line-no">1017</span><span id="line-1017"> flushed = true;</span>
+<span class="source-line-no">1018</span><span id="line-1018"> final boolean isCompaction = false;</span>
+<span class="source-line-no">1019</span><span id="line-1019"> boolean usePread = get || scanUsePread;</span>
+<span class="source-line-no">1020</span><span id="line-1020"> // SEE HBASE-19468 where the flushed files are getting compacted even before a scanner</span>
+<span class="source-line-no">1021</span><span id="line-1021"> // calls next(). So its better we create scanners here rather than next() call. Ensure</span>
+<span class="source-line-no">1022</span><span id="line-1022"> // these scanners are properly closed() whether or not the scan is completed successfully</span>
+<span class="source-line-no">1023</span><span id="line-1023"> // Eagerly creating scanners so that we have the ref counting ticking on the newly created</span>
+<span class="source-line-no">1024</span><span id="line-1024"> // store files. In case of stream scanners this eager creation does not induce performance</span>
+<span class="source-line-no">1025</span><span id="line-1025"> // penalty because in scans (that uses stream scanners) the next() call is bound to happen.</span>
+<span class="source-line-no">1026</span><span id="line-1026"> List<KeyValueScanner> scanners =</span>
+<span class="source-line-no">1027</span><span id="line-1027"> store.getScanners(sfs, cacheBlocks, get, usePread, isCompaction, matcher,</span>
+<span class="source-line-no">1028</span><span id="line-1028"> scan.getStartRow(), scan.getStopRow(), this.readPt, false, isOnlyLatestVersionScan(scan));</span>
+<span class="source-line-no">1029</span><span id="line-1029"> flushedstoreFileScanners.addAll(scanners);</span>
+<span class="source-line-no">1030</span><span id="line-1030"> if (!CollectionUtils.isEmpty(memStoreScanners)) {</span>
+<span class="source-line-no">1031</span><span id="line-1031"> clearAndClose(memStoreScannersAfterFlush);</span>
+<span class="source-line-no">1032</span><span id="line-1032"> memStoreScannersAfterFlush.addAll(memStoreScanners);</span>
+<span class="source-line-no">1033</span><span id="line-1033"> }</span>
+<span class="source-line-no">1034</span><span id="line-1034"> } finally {</span>
+<span class="source-line-no">1035</span><span id="line-1035"> flushLock.unlock();</span>
+<span class="source-line-no">1036</span><span id="line-1036"> if (updateReaders) {</span>
+<span class="source-line-no">1037</span><span id="line-1037"> closeLock.unlock();</span>
+<span class="source-line-no">1038</span><span id="line-1038"> }</span>
+<span class="source-line-no">1039</span><span id="line-1039"> if (hasUpdatedReaders != null) {</span>
+<span class="source-line-no">1040</span><span id="line-1040"> hasUpdatedReaders.set(true);</span>
+<span class="source-line-no">1041</span><span id="line-1041"> }</span>
+<span class="source-line-no">1042</span><span id="line-1042"> }</span>
+<span class="source-line-no">1043</span><span id="line-1043"> // Let the next() call handle re-creating and seeking</span>
+<span class="source-line-no">1044</span><span id="line-1044"> }</span>
+<span class="source-line-no">1045</span><span id="line-1045"></span>
+<span class="source-line-no">1046</span><span id="line-1046"> /** Returns if top of heap has changed (and KeyValueHeap has to try the next KV) */</span>
+<span class="source-line-no">1047</span><span id="line-1047"> protected final boolean reopenAfterFlush() throws IOException {</span>
+<span class="source-line-no">1048</span><span id="line-1048"> // here we can make sure that we have a Store instance so no null check on store.</span>
+<span class="source-line-no">1049</span><span id="line-1049"> ExtendedCell lastTop = heap.peek();</span>
+<span class="source-line-no">1050</span><span id="line-1050"> // When we have the scan object, should we not pass it to getScanners() to get a limited set of</span>
+<span class="source-line-no">1051</span><span id="line-1051"> // scanners? We did so in the constructor and we could have done it now by storing the scan</span>
+<span class="source-line-no">1052</span><span id="line-1052"> // object from the constructor</span>
+<span class="source-line-no">1053</span><span id="line-1053"> List<KeyValueScanner> scanners;</span>
+<span class="source-line-no">1054</span><span id="line-1054"> flushLock.lock();</span>
+<span class="source-line-no">1055</span><span id="line-1055"> try {</span>
+<span class="source-line-no">1056</span><span id="line-1056"> List<KeyValueScanner> allScanners =</span>
+<span class="source-line-no">1057</span><span id="line-1057"> new ArrayList<>(flushedstoreFileScanners.size() + memStoreScannersAfterFlush.size());</span>
+<span class="source-line-no">1058</span><span id="line-1058"> allScanners.addAll(flushedstoreFileScanners);</span>
+<span class="source-line-no">1059</span><span id="line-1059"> allScanners.addAll(memStoreScannersAfterFlush);</span>
+<span class="source-line-no">1060</span><span id="line-1060"> scanners = selectScannersFrom(store, allScanners);</span>
+<span class="source-line-no">1061</span><span id="line-1061"> // Clear the current set of flushed store files scanners so that they don't get added again</span>
+<span class="source-line-no">1062</span><span id="line-1062"> flushedstoreFileScanners.clear();</span>
+<span class="source-line-no">1063</span><span id="line-1063"> memStoreScannersAfterFlush.clear();</span>
+<span class="source-line-no">1064</span><span id="line-1064"> } finally {</span>
+<span class="source-line-no">1065</span><span id="line-1065"> flushLock.unlock();</span>
+<span class="source-line-no">1066</span><span id="line-1066"> }</span>
+<span class="source-line-no">1067</span><span id="line-1067"></span>
+<span class="source-line-no">1068</span><span id="line-1068"> // Seek the new scanners to the last key</span>
+<span class="source-line-no">1069</span><span id="line-1069"> seekScanners(scanners, lastTop, false, parallelSeekEnabled);</span>
+<span class="source-line-no">1070</span><span id="line-1070"> // remove the older memstore scanner</span>
+<span class="source-line-no">1071</span><span id="line-1071"> for (int i = currentScanners.size() - 1; i >= 0; i--) {</span>
+<span class="source-line-no">1072</span><span id="line-1072"> if (!currentScanners.get(i).isFileScanner()) {</span>
+<span class="source-line-no">1073</span><span id="line-1073"> scannersForDelayedClose.add(currentScanners.remove(i));</span>
+<span class="source-line-no">1074</span><span id="line-1074"> } else {</span>
+<span class="source-line-no">1075</span><span id="line-1075"> // we add the memstore scanner to the end of currentScanners</span>
+<span class="source-line-no">1076</span><span id="line-1076"> break;</span>
+<span class="source-line-no">1077</span><span id="line-1077"> }</span>
+<span class="source-line-no">1078</span><span id="line-1078"> }</span>
+<span class="source-line-no">1079</span><span id="line-1079"> // add the newly created scanners on the flushed files and the current active memstore scanner</span>
+<span class="source-line-no">1080</span><span id="line-1080"> addCurrentScanners(scanners);</span>
+<span class="source-line-no">1081</span><span id="line-1081"> // Combine all seeked scanners with a heap</span>
+<span class="source-line-no">1082</span><span id="line-1082"> resetKVHeap(this.currentScanners, store.getComparator());</span>
+<span class="source-line-no">1083</span><span id="line-1083"> resetQueryMatcher(lastTop);</span>
+<span class="source-line-no">1084</span><span id="line-1084"> if (heap.peek() == null || store.getComparator().compareRows(lastTop, this.heap.peek()) != 0) {</span>
+<span class="source-line-no">1085</span><span id="line-1085"> LOG.info("Storescanner.peek() is changed where before = " + lastTop.toString()</span>
+<span class="source-line-no">1086</span><span id="line-1086"> + ",and after = " + heap.peek());</span>
+<span class="source-line-no">1087</span><span id="line-1087"> topChanged = true;</span>
+<span class="source-line-no">1088</span><span id="line-1088"> } else {</span>
+<span class="source-line-no">1089</span><span id="line-1089"> topChanged = false;</span>
+<span class="source-line-no">1090</span><span id="line-1090"> }</span>
+<span class="source-line-no">1091</span><span id="line-1091"> return topChanged;</span>
+<span class="source-line-no">1092</span><span id="line-1092"> }</span>
+<span class="source-line-no">1093</span><span id="line-1093"></span>
+<span class="source-line-no">1094</span><span id="line-1094"> private void resetQueryMatcher(ExtendedCell lastTopKey) {</span>
+<span class="source-line-no">1095</span><span id="line-1095"> // Reset the state of the Query Matcher and set to top row.</span>
+<span class="source-line-no">1096</span><span id="line-1096"> // Only reset and call setRow if the row changes; avoids confusing the</span>
+<span class="source-line-no">1097</span><span id="line-1097"> // query matcher if scanning intra-row.</span>
+<span class="source-line-no">1098</span><span id="line-1098"> ExtendedCell cell = heap.peek();</span>
+<span class="source-line-no">1099</span><span id="line-1099"> if (cell == null) {</span>
+<span class="source-line-no">1100</span><span id="line-1100"> cell = lastTopKey;</span>
+<span class="source-line-no">1101</span><span id="line-1101"> }</span>
+<span class="source-line-no">1102</span><span id="line-1102"> if ((matcher.currentRow() == null) || !CellUtil.matchingRows(cell, matcher.currentRow())) {</span>
+<span class="source-line-no">1103</span><span id="line-1103"> this.countPerRow = 0;</span>
+<span class="source-line-no">1104</span><span id="line-1104"> // The setToNewRow will call reset internally</span>
+<span class="source-line-no">1105</span><span id="line-1105"> matcher.setToNewRow(cell);</span>
+<span class="source-line-no">1106</span><span id="line-1106"> }</span>
+<span class="source-line-no">1107</span><span id="line-1107"> }</span>
+<span class="source-line-no">1108</span><span id="line-1108"></span>
+<span class="source-line-no">1109</span><span id="line-1109"> /**</span>
+<span class="source-line-no">1110</span><span id="line-1110"> * Check whether scan as expected order</span>
+<span class="source-line-no">1111</span><span id="line-1111"> */</span>
+<span class="source-line-no">1112</span><span id="line-1112"> protected void checkScanOrder(Cell prevKV, Cell kv, CellComparator comparator)</span>
+<span class="source-line-no">1113</span><span id="line-1113"> throws IOException {</span>
+<span class="source-line-no">1114</span><span id="line-1114"> // Check that the heap gives us KVs in an increasing order.</span>
+<span class="source-line-no">1115</span><span id="line-1115"> assert prevKV == null || comparator == null || comparator.compare(prevKV, kv) <= 0</span>
+<span class="source-line-no">1116</span><span id="line-1116"> : "Key " + prevKV + " followed by a smaller key " + kv + " in cf " + store;</span>
+<span class="source-line-no">1117</span><span id="line-1117"> }</span>
+<span class="source-line-no">1118</span><span id="line-1118"></span>
+<span class="source-line-no">1119</span><span id="line-1119"> protected boolean seekToNextRow(ExtendedCell c) throws IOException {</span>
+<span class="source-line-no">1120</span><span id="line-1120"> return reseek(PrivateCellUtil.createLastOnRow(c));</span>
+<span class="source-line-no">1121</span><span id="line-1121"> }</span>
+<span class="source-line-no">1122</span><span id="line-1122"></span>
+<span class="source-line-no">1123</span><span id="line-1123"> /**</span>
+<span class="source-line-no">1124</span><span id="line-1124"> * Do a reseek in a normal StoreScanner(scan forward)</span>
+<span class="source-line-no">1125</span><span id="line-1125"> * @return true if scanner has values left, false if end of scanner</span>
+<span class="source-line-no">1126</span><span id="line-1126"> */</span>
+<span class="source-line-no">1127</span><span id="line-1127"> protected boolean seekAsDirection(ExtendedCell kv) throws IOException {</span>
+<span class="source-line-no">1128</span><span id="line-1128"> return reseek(kv);</span>
+<span class="source-line-no">1129</span><span id="line-1129"> }</span>
+<span class="source-line-no">1130</span><span id="line-1130"></span>
+<span class="source-line-no">1131</span><span id="line-1131"> @Override</span>
+<span class="source-line-no">1132</span><span id="line-1132"> public boolean reseek(ExtendedCell kv) throws IOException {</span>
+<span class="source-line-no">1133</span><span id="line-1133"> if (checkFlushed()) {</span>
+<span class="source-line-no">1134</span><span id="line-1134"> reopenAfterFlush();</span>
+<span class="source-line-no">1135</span><span id="line-1135"> }</span>
+<span class="source-line-no">1136</span><span id="line-1136"> if (explicitColumnQuery && lazySeekEnabledGlobally) {</span>
+<span class="source-line-no">1137</span><span id="line-1137"> return heap.requestSeek(kv, true, useRowColBloom);</span>
+<span class="source-line-no">1138</span><span id="line-1138"> }</span>
+<span class="source-line-no">1139</span><span id="line-1139"> return heap.reseek(kv);</span>
+<span class="source-line-no">1140</span><span id="line-1140"> }</span>
+<span class="source-line-no">1141</span><span id="line-1141"></span>
+<span class="source-line-no">1142</span><span id="line-1142"> void trySwitchToStreamRead() {</span>
+<span class="source-line-no">1143</span><span id="line-1143"> if (</span>
+<span class="source-line-no">1144</span><span id="line-1144"> readType != Scan.ReadType.DEFAULT || !scanUsePread || closing || heap.peek() == null</span>
+<span class="source-line-no">1145</span><span id="line-1145"> || bytesRead < preadMaxBytes</span>
+<span class="source-line-no">1146</span><span id="line-1146"> ) {</span>
+<span class="source-line-no">1147</span><span id="line-1147"> return;</span>
+<span class="source-line-no">1148</span><span id="line-1148"> }</span>
+<span class="source-line-no">1149</span><span id="line-1149"> LOG.debug("Switch to stream read (scanned={} bytes) of {}", bytesRead,</span>
+<span class="source-line-no">1150</span><span id="line-1150"> this.store.getColumnFamilyName());</span>
+<span class="source-line-no">1151</span><span id="line-1151"> scanUsePread = false;</span>
+<span class="source-line-no">1152</span><span id="line-1152"> ExtendedCell lastTop = heap.peek();</span>
+<span class="source-line-no">1153</span><span id="line-1153"> List<KeyValueScanner> memstoreScanners = new ArrayList<>();</span>
+<span class="source-line-no">1154</span><span id="line-1154"> List<KeyValueScanner> scannersToClose = new ArrayList<>();</span>
+<span class="source-line-no">1155</span><span id="line-1155"> for (KeyValueScanner kvs : currentScanners) {</span>
+<span class="source-line-no">1156</span><span id="line-1156"> if (!kvs.isFileScanner()) {</span>
+<span class="source-line-no">1157</span><span id="line-1157"> // collect memstorescanners here</span>
+<span class="source-line-no">1158</span><span id="line-1158"> memstoreScanners.add(kvs);</span>
+<span class="source-line-no">1159</span><span id="line-1159"> } else {</span>
+<span class="source-line-no">1160</span><span id="line-1160"> scannersToClose.add(kvs);</span>
+<span class="source-line-no">1161</span><span id="line-1161"> }</span>
+<span class="source-line-no">1162</span><span id="line-1162"> }</span>
+<span class="source-line-no">1163</span><span id="line-1163"> List<KeyValueScanner> fileScanners = null;</span>
+<span class="source-line-no">1164</span><span id="line-1164"> List<KeyValueScanner> newCurrentScanners;</span>
+<span class="source-line-no">1165</span><span id="line-1165"> KeyValueHeap newHeap;</span>
+<span class="source-line-no">1166</span><span id="line-1166"> try {</span>
+<span class="source-line-no">1167</span><span id="line-1167"> // We must have a store instance here so no null check</span>
+<span class="source-line-no">1168</span><span id="line-1168"> // recreate the scanners on the current file scanners</span>
+<span class="source-line-no">1169</span><span id="line-1169"> fileScanners = store.recreateScanners(scannersToClose, cacheBlocks, false, false, matcher,</span>
+<span class="source-line-no">1170</span><span id="line-1170"> scan.getStartRow(), scan.includeStartRow(), scan.getStopRow(), scan.includeStopRow(),</span>
+<span class="source-line-no">1171</span><span id="line-1171"> readPt, false);</span>
+<span class="source-line-no">1172</span><span id="line-1172"> if (fileScanners == null) {</span>
+<span class="source-line-no">1173</span><span id="line-1173"> return;</span>
+<span class="source-line-no">1174</span><span id="line-1174"> }</span>
+<span class="source-line-no">1175</span><span id="line-1175"> seekScanners(fileScanners, lastTop, false, parallelSeekEnabled);</span>
+<span class="source-line-no">1176</span><span id="line-1176"> newCurrentScanners = new ArrayList<>(fileScanners.size() + memstoreScanners.size());</span>
+<span class="source-line-no">1177</span><span id="line-1177"> newCurrentScanners.addAll(fileScanners);</span>
+<span class="source-line-no">1178</span><span id="line-1178"> newCurrentScanners.addAll(memstoreScanners);</span>
+<span class="source-line-no">1179</span><span id="line-1179"> newHeap = newKVHeap(newCurrentScanners, comparator);</span>
+<span class="source-line-no">1180</span><span id="line-1180"> } catch (Exception e) {</span>
+<span class="source-line-no">1181</span><span id="line-1181"> LOG.warn("failed to switch to stream read", e);</span>
+<span class="source-line-no">1182</span><span id="line-1182"> if (fileScanners != null) {</span>
+<span class="source-line-no">1183</span><span id="line-1183"> fileScanners.forEach(KeyValueScanner::close);</span>
+<span class="source-line-no">1184</span><span id="line-1184"> }</span>
+<span class="source-line-no">1185</span><span id="line-1185"> return;</span>
+<span class="source-line-no">1186</span><span id="line-1186"> }</span>
+<span class="source-line-no">1187</span><span id="line-1187"> currentScanners.clear();</span>
+<span class="source-line-no">1188</span><span id="line-1188"> addCurrentScanners(newCurrentScanners);</span>
+<span class="source-line-no">1189</span><span id="line-1189"> this.heap = newHeap;</span>
+<span class="source-line-no">1190</span><span id="line-1190"> resetQueryMatcher(lastTop);</span>
+<span class="source-line-no">1191</span><span id="line-1191"> scannersToClose.forEach(KeyValueScanner::close);</span>
+<span class="source-line-no">1192</span><span id="line-1192"> if (hasSwitchedToStreamRead != null) {</span>
+<span class="source-line-no">1193</span><span id="line-1193"> hasSwitchedToStreamRead.set(true);</span>
+<span class="source-line-no">1194</span><span id="line-1194"> }</span>
+<span class="source-line-no">1195</span><span id="line-1195"> }</span>
+<span class="source-line-no">1196</span><span id="line-1196"></span>
+<span class="source-line-no">1197</span><span id="line-1197"> protected final boolean checkFlushed() {</span>
+<span class="source-line-no">1198</span><span id="line-1198"> // check the var without any lock. Suppose even if we see the old</span>
+<span class="source-line-no">1199</span><span id="line-1199"> // value here still it is ok to continue because we will not be resetting</span>
+<span class="source-line-no">1200</span><span id="line-1200"> // the heap but will continue with the referenced memstore's snapshot. For compactions</span>
+<span class="source-line-no">1201</span><span id="line-1201"> // any way we don't need the updateReaders at all to happen as we still continue with</span>
+<span class="source-line-no">1202</span><span id="line-1202"> // the older files</span>
+<span class="source-line-no">1203</span><span id="line-1203"> if (flushed) {</span>
+<span class="source-line-no">1204</span><span id="line-1204"> // If there is a flush and the current scan is notified on the flush ensure that the</span>
+<span class="source-line-no">1205</span><span id="line-1205"> // scan's heap gets reset and we do a seek on the newly flushed file.</span>
+<span class="source-line-no">1206</span><span id="line-1206"> if (this.closing) {</span>
+<span class="source-line-no">1207</span><span id="line-1207"> return false;</span>
+<span class="source-line-no">1208</span><span id="line-1208"> }</span>
+<span class="source-line-no">1209</span><span id="line-1209"> // reset the flag</span>
+<span class="source-line-no">1210</span><span id="line-1210"> flushed = false;</span>
+<span class="source-line-no">1211</span><span id="line-1211"> return true;</span>
+<span class="source-line-no">1212</span><span id="line-1212"> }</span>
+<span class="source-line-no">1213</span><span id="line-1213"> return false;</span>
+<span class="source-line-no">1214</span><span id="line-1214"> }</span>
+<span class="source-line-no">1215</span><span id="line-1215"></span>
+<span class="source-line-no">1216</span><span id="line-1216"> /**</span>
+<span class="source-line-no">1217</span><span id="line-1217"> * Seek storefiles in parallel to optimize IO latency as much as possible</span>
+<span class="source-line-no">1218</span><span id="line-1218"> * @param scanners the list {@link KeyValueScanner}s to be read from</span>
+<span class="source-line-no">1219</span><span id="line-1219"> * @param kv the KeyValue on which the operation is being requested</span>
+<span class="source-line-no">1220</span><span id="line-1220"> */</span>
+<span class="source-line-no">1221</span><span id="line-1221"> private void parallelSeek(final List<? extends KeyValueScanner> scanners, final ExtendedCell kv)</span>
+<span class="source-line-no">1222</span><span id="line-1222"> throws IOException {</span>
+<span class="source-line-no">1223</span><span id="line-1223"> if (scanners.isEmpty()) return;</span>
+<span class="source-line-no">1224</span><span id="line-1224"> int storeFileScannerCount = scanners.size();</span>
+<span class="source-line-no">1225</span><span id="line-1225"> CountDownLatch latch = new CountDownLatch(storeFileScannerCount);</span>
+<span class="source-line-no">1226</span><span id="line-1226"> List<ParallelSeekHandler> handlers = new ArrayList<>(storeFileScannerCount);</span>
+<span class="source-line-no">1227</span><span id="line-1227"> for (KeyValueScanner scanner : scanners) {</span>
+<span class="source-line-no">1228</span><span id="line-1228"> if (scanner instanceof StoreFileScanner) {</span>
+<span class="source-line-no">1229</span><span id="line-1229"> ParallelSeekHandler seekHandler = new ParallelSeekHandler(scanner, kv, this.readPt, latch);</span>
+<span class="source-line-no">1230</span><span id="line-1230"> executor.submit(seekHandler);</span>
+<span class="source-line-no">1231</span><span id="line-1231"> handlers.add(seekHandler);</span>
+<span class="source-line-no">1232</span><span id="line-1232"> } else {</span>
+<span class="source-line-no">1233</span><span id="line-1233"> scanner.seek(kv);</span>
+<span class="source-line-no">1234</span><span id="line-1234"> latch.countDown();</span>
+<span class="source-line-no">1235</span><span id="line-1235"> }</span>
+<span class="source-line-no">1236</span><span id="line-1236"> }</span>
+<span class="source-line-no">1237</span><span id="line-1237"></span>
+<span class="source-line-no">1238</span><span id="line-1238"> try {</span>
+<span class="source-line-no">1239</span><span id="line-1239"> latch.await();</span>
+<span class="source-line-no">1240</span><span id="line-1240"> } catch (InterruptedException ie) {</span>
+<span class="source-line-no">1241</span><span id="line-1241"> throw (InterruptedIOException) new InterruptedIOException().initCause(ie);</span>
+<span class="source-line-no">1242</span><span id="line-1242"> }</span>
+<span class="source-line-no">1243</span><span id="line-1243"></span>
+<span class="source-line-no">1244</span><span id="line-1244"> for (ParallelSeekHandler handler : handlers) {</span>
+<span class="source-line-no">1245</span><span id="line-1245"> if (handler.getErr() != null) {</span>
+<span class="source-line-no">1246</span><span id="line-1246"> throw new IOException(handler.getErr());</span>
+<span class="source-line-no">1247</span><span id="line-1247"> }</span>
+<span class="source-line-no">1248</span><span id="line-1248"> }</span>
+<span class="source-line-no">1249</span><span id="line-1249"> }</span>
+<span class="source-line-no">1250</span><span id="line-1250"></span>
+<span class="source-line-no">1251</span><span id="line-1251"> /**</span>
+<span class="source-line-no">1252</span><span id="line-1252"> * Used in testing.</span>
+<span class="source-line-no">1253</span><span id="line-1253"> * @return all scanners in no particular order</span>
+<span class="source-line-no">1254</span><span id="line-1254"> */</span>
+<span class="source-line-no">1255</span><span id="line-1255"> List<KeyValueScanner> getAllScannersForTesting() {</span>
+<span class="source-line-no">1256</span><span id="line-1256"> List<KeyValueScanner> allScanners = new ArrayList<>();</span>
+<span class="source-line-no">1257</span><span id="line-1257"> KeyValueScanner current = heap.getCurrentForTesting();</span>
+<span class="source-line-no">1258</span><span id="line-1258"> if (current != null) allScanners.add(current);</span>
+<span class="source-line-no">1259</span><span id="line-1259"> for (KeyValueScanner scanner : heap.getHeap())</span>
+<span class="source-line-no">1260</span><span id="line-1260"> allScanners.add(scanner);</span>
+<span class="source-line-no">1261</span><span id="line-1261"> return allScanners;</span>
+<span class="source-line-no">1262</span><span id="line-1262"> }</span>
+<span class="source-line-no">1263</span><span id="line-1263"></span>
+<span class="source-line-no">1264</span><span id="line-1264"> static void enableLazySeekGlobally(boolean enable) {</span>
+<span class="source-line-no">1265</span><span id="line-1265"> lazySeekEnabledGlobally = enable;</span>
+<span class="source-line-no">1266</span><span id="line-1266"> }</span>
+<span class="source-line-no">1267</span><span id="line-1267"></span>
+<span class="source-line-no">1268</span><span id="line-1268"> /** Returns The estimated number of KVs seen by this scanner (includes some skipped KVs). */</span>
+<span class="source-line-no">1269</span><span id="line-1269"> public long getEstimatedNumberOfKvsScanned() {</span>
+<span class="source-line-no">1270</span><span id="line-1270"> return this.kvsScanned;</span>
+<span class="source-line-no">1271</span><span id="line-1271"> }</span>
+<span class="source-line-no">1272</span><span id="line-1272"></span>
+<span class="source-line-no">1273</span><span id="line-1273"> @Override</span>
+<span class="source-line-no">1274</span><span id="line-1274"> public ExtendedCell getNextIndexedKey() {</span>
+<span class="source-line-no">1275</span><span id="line-1275"> return this.heap.getNextIndexedKey();</span>
+<span class="source-line-no">1276</span><span id="line-1276"> }</span>
+<span class="source-line-no">1277</span><span id="line-1277"></span>
+<span class="source-line-no">1278</span><span id="line-1278"> @Override</span>
+<span class="source-line-no">1279</span><span id="line-1279"> public void shipped() throws IOException {</span>
+<span class="source-line-no">1280</span><span id="line-1280"> if (prevCell != null) {</span>
+<span class="source-line-no">1281</span><span id="line-1281"> // Do the copy here so that in case the prevCell ref is pointing to the previous</span>
+<span class="source-line-no">1282</span><span id="line-1282"> // blocks we can safely release those blocks.</span>
+<span class="source-line-no">1283</span><span id="line-1283"> // This applies to blocks that are got from Bucket cache, L1 cache and the blocks</span>
+<span class="source-line-no">1284</span><span id="line-1284"> // fetched from HDFS. Copying this would ensure that we let go the references to these</span>
+<span class="source-line-no">1285</span><span id="line-1285"> // blocks so that they can be GCed safely(in case of bucket cache)</span>
+<span class="source-line-no">1286</span><span id="line-1286"> prevCell = KeyValueUtil.toNewKeyCell(this.prevCell);</span>
+<span class="source-line-no">1287</span><span id="line-1287"> }</span>
+<span class="source-line-no">1288</span><span id="line-1288"> matcher.beforeShipped();</span>
+<span class="source-line-no">1289</span><span id="line-1289"> // There wont be further fetch of Cells from these scanners. Just close.</span>
+<span class="source-line-no">1290</span><span id="line-1290"> clearAndClose(scannersForDelayedClose);</span>
+<span class="source-line-no">1291</span><span id="line-1291"> if (this.heap != null) {</span>
+<span class="source-line-no">1292</span><span id="line-1292"> this.heap.shipped();</span>
+<span class="source-line-no">1293</span><span id="line-1293"> // When switching from pread to stream, we will open a new scanner for each store file, but</span>
+<span class="source-line-no">1294</span><span id="line-1294"> // the old scanner may still track the HFileBlocks we have scanned but not sent back to client</span>
+<span class="source-line-no">1295</span><span id="line-1295"> // yet. If we close the scanner immediately then the HFileBlocks may be messed up by others</span>
+<span class="source-line-no">1296</span><span id="line-1296"> // before we serialize and send it back to client. The HFileBlocks will be released in shipped</span>
+<span class="source-line-no">1297</span><span id="line-1297"> // method, so we here will also open new scanners and close old scanners in shipped method.</span>
+<span class="source-line-no">1298</span><span id="line-1298"> // See HBASE-18055 for more details.</span>
+<span class="source-line-no">1299</span><span id="line-1299"> trySwitchToStreamRead();</span>
+<span class="source-line-no">1300</span><span id="line-1300"> }</span>
+<span class="source-line-no">1301</span><span id="line-1301"> }</span>
+<span class="source-line-no">1302</span><span id="line-1302"></span>
+<span class="source-line-no">1303</span><span id="line-1303"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1304</span><span id="line-1304"> static final void instrument() {</span>
+<span class="source-line-no">1305</span><span id="line-1305"> hasUpdatedReaders = new AtomicBoolean(false);</span>
+<span class="source-line-no">1306</span><span id="line-1306"> hasSwitchedToStreamRead = new AtomicBoolean(false);</span>
+<span class="source-line-no">1307</span><span id="line-1307"> }</span>
+<span class="source-line-no">1308</span><span id="line-1308"></span>
+<span class="source-line-no">1309</span><span id="line-1309"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1310</span><span id="line-1310"> static final boolean hasUpdatedReaders() {</span>
+<span class="source-line-no">1311</span><span id="line-1311"> return hasUpdatedReaders.get();</span>
+<span class="source-line-no">1312</span><span id="line-1312"> }</span>
+<span class="source-line-no">1313</span><span id="line-1313"></span>
+<span class="source-line-no">1314</span><span id="line-1314"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1315</span><span id="line-1315"> static final boolean hasSwitchedToStreamRead() {</span>
+<span class="source-line-no">1316</span><span id="line-1316"> return hasSwitchedToStreamRead.get();</span>
+<span class="source-line-no">1317</span><span id="line-1317"> }</span>
+<span class="source-line-no">1318</span><span id="line-1318"></span>
+<span class="source-line-no">1319</span><span id="line-1319"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1320</span><span id="line-1320"> static final void resetHasUpdatedReaders() {</span>
+<span class="source-line-no">1321</span><span id="line-1321"> hasUpdatedReaders.set(false);</span>
+<span class="source-line-no">1322</span><span id="line-1322"> }</span>
+<span class="source-line-no">1323</span><span id="line-1323"></span>
+<span class="source-line-no">1324</span><span id="line-1324"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1325</span><span id="line-1325"> static final void resetHasSwitchedToStreamRead() {</span>
+<span class="source-line-no">1326</span><span id="line-1326"> hasSwitchedToStreamRead.set(false);</span>
+<span class="source-line-no">1327</span><span id="line-1327"> }</span>
+<span class="source-line-no">1328</span><span id="line-1328">}</span>
diff --git a/book.html b/book.html
index 6f7c154931e..804d3e3d70f 100644
--- a/book.html
+++ b/book.html
@@ -50192,7 +50192,7 @@ org/apache/hadoop/hbase/security/access/AccessControlClient.revoke:(Lorg/apache/
<div id="footer">
<div id="footer-text">
Version 4.0.0-alpha-1-SNAPSHOT<br>
-Last updated 2026-02-25 14:31:29 UTC
+Last updated 2026-02-26 14:31:22 UTC
</div>
</div>
<script type="text/x-mathjax-config">
diff --git a/checkstyle-aggregate.html b/checkstyle-aggregate.html
index 9244f4d1a6d..7559fccce78 100644
--- a/checkstyle-aggregate.html
+++ b/checkstyle-aggregate.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-checkstyle-plugin:3.6.0:checkstyle-aggregate at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-checkstyle-plugin:3.6.0:checkstyle-aggregate at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
@@ -14231,19 +14231,19 @@
<td>blocks</td>
<td>NeedBraces</td>
<td>'if' construct must use '{}'s.</td>
-<td>1225</td></tr>
+<td>1223</td></tr>
<tr class="b">
<td><img src="images/icon_error_sml.gif" /> Error</td>
<td>blocks</td>
<td>NeedBraces</td>
<td>'if' construct must use '{}'s.</td>
-<td>1260</td></tr>
+<td>1258</td></tr>
<tr class="a">
<td><img src="images/icon_error_sml.gif" /> Error</td>
<td>blocks</td>
<td>NeedBraces</td>
<td>'for' construct must use '{}'s.</td>
-<td>1261</td></tr></table></section><section><a id="org.2Fapache.2Fhadoop.2Fhbase.2Fregionserver.2FStorefileRefresherChore.java"></a>
+<td>1259</td></tr></table></section><section><a id="org.2Fapache.2Fhadoop.2Fhbase.2Fregionserver.2FStorefileRefresherChore.java"></a>
<h3>org/apache/hadoop/hbase/regionserver/StorefileRefresherChore.java</h3>
<table class="table table-striped">
<tr class="a">
diff --git a/dependency-convergence.html b/dependency-convergence.html
index dcd41f2c1df..b9bf7a5743e 100644
--- a/dependency-convergence.html
+++ b/dependency-convergence.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-convergence at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-convergence at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/dependency-info.html b/dependency-info.html
index 30ef4698ac9..9bf5d46dc0c 100644
--- a/dependency-info.html
+++ b/dependency-info.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-info at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-info at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/dependency-management.html b/dependency-management.html
index 69b450a54d2..da5b51f9321 100644
--- a/dependency-management.html
+++ b/dependency-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/devapidocs/org/apache/hadoop/hbase/regionserver/StoreScanner.html b/devapidocs/org/apache/hadoop/hbase/regionserver/StoreScanner.html
index 991ffcf1998..80726b0f2f1 100644
--- a/devapidocs/org/apache/hadoop/hbase/regionserver/StoreScanner.html
+++ b/devapidocs/org/apache/hadoop/hbase/regionserver/StoreScanner.html
@@ -1370,7 +1370,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="getReadPoint()">
<h3>getReadPoint</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">long</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-976">getReadPoint</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">long</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-974">getReadPoint</a></span>()</div>
<div class="block"><span class="descfrm-type-label">Description copied from interface: <code><a href="ChangedReadersObserver.html#getReadPoint()">ChangedReadersObserver</a></code></span></div>
<div class="block">Returns the read point of the current scan</div>
<dl class="notes">
@@ -1382,13 +1382,13 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="clearAndClose(java.util.List)">
<h3>clearAndClose</h3>
-<div class="member-signature"><span class="modifiers">private static</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-981">clearAndClose</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="KeyValueScanne [...]
+<div class="member-signature"><span class="modifiers">private static</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-979">clearAndClose</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="KeyValueScanne [...]
</section>
</li>
<li>
<section class="detail" id="updateReaders(java.util.List,java.util.List)">
<h3>updateReaders</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-992">updateReaders</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="HStoreFile.html" title [...]
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-990">updateReaders</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="HStoreFile.html" title [...]
<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>> memStoreScanners)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block"><span class="descfrm-type-label">Description copied from interface: <code><a href="ChangedReadersObserver.html#updateReaders(java.util.List,java.util.List)">ChangedReadersObserver</a></code></span></div>
@@ -1413,7 +1413,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="reopenAfterFlush()">
<h3>reopenAfterFlush</h3>
-<div class="member-signature"><span class="modifiers">protected final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1049">reopenAfterFlush</a></span>()
+<div class="member-signature"><span class="modifiers">protected final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1047">reopenAfterFlush</a></span>()
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block">Returns if top of heap has changed (and KeyValueHeap has to try the next KV)</div>
<dl class="notes">
@@ -1425,13 +1425,13 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="resetQueryMatcher(org.apache.hadoop.hbase.ExtendedCell)">
<h3>resetQueryMatcher</h3>
-<div class="member-signature"><span class="modifiers">private</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1096">resetQueryMatcher</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> lastTopKey)</span></div>
+<div class="member-signature"><span class="modifiers">private</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1094">resetQueryMatcher</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> lastTopKey)</span></div>
</section>
</li>
<li>
<section class="detail" id="checkScanOrder(org.apache.hadoop.hbase.Cell,org.apache.hadoop.hbase.Cell,org.apache.hadoop.hbase.CellComparator)">
<h3>checkScanOrder</h3>
-<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1114">checkScanOrder</a></span><wbr><span class="parameters">(<a href="../Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a> prevKV,
+<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1112">checkScanOrder</a></span><wbr><span class="parameters">(<a href="../Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a> prevKV,
<a href="../Cell.html" title="interface in org.apache.hadoop.hbase">Cell</a> kv,
<a href="../CellComparator.html" title="interface in org.apache.hadoop.hbase">CellComparator</a> comparator)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
@@ -1445,7 +1445,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="seekToNextRow(org.apache.hadoop.hbase.ExtendedCell)">
<h3>seekToNextRow</h3>
-<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1121">seekToNextRow</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> c)</span>
+<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1119">seekToNextRow</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> c)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<dl class="notes">
<dt>Throws:</dt>
@@ -1456,7 +1456,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="seekAsDirection(org.apache.hadoop.hbase.ExtendedCell)">
<h3>seekAsDirection</h3>
-<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1129">seekAsDirection</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> kv)</span>
+<div class="member-signature"><span class="modifiers">protected</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1127">seekAsDirection</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> kv)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block">Do a reseek in a normal StoreScanner(scan forward)</div>
<dl class="notes">
@@ -1470,7 +1470,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="reseek(org.apache.hadoop.hbase.ExtendedCell)">
<h3>reseek</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1133">reseek</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> kv)</span>
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1131">reseek</a></span><wbr><span class="parameters">(<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> kv)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block"><span class="descfrm-type-label">Description copied from interface: <code><a href="KeyValueScanner.html#reseek(org.apache.hadoop.hbase.ExtendedCell)">KeyValueScanner</a></code></span></div>
<div class="block">Reseek the scanner at or after the specified KeyValue. This method is guaranteed to seek at or
@@ -1491,19 +1491,19 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="trySwitchToStreamRead()">
<h3>trySwitchToStreamRead</h3>
-<div class="member-signature"><span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1144">trySwitchToStreamRead</a></span>()</div>
+<div class="member-signature"><span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1142">trySwitchToStreamRead</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="checkFlushed()">
<h3>checkFlushed</h3>
-<div class="member-signature"><span class="modifiers">protected final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1199">checkFlushed</a></span>()</div>
+<div class="member-signature"><span class="modifiers">protected final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1197">checkFlushed</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="parallelSeek(java.util.List,org.apache.hadoop.hbase.ExtendedCell)">
<h3>parallelSeek</h3>
-<div class="member-signature"><span class="modifiers">private</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1223">parallelSeek</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><? extends <a href="KeyValueSca [...]
+<div class="member-signature"><span class="modifiers">private</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1221">parallelSeek</a></span><wbr><span class="parameters">(<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><? extends <a href="KeyValueSca [...]
<a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a> kv)</span>
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block">Seek storefiles in parallel to optimize IO latency as much as possible</div>
@@ -1519,7 +1519,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="getAllScannersForTesting()">
<h3>getAllScannersForTesting</h3>
-<div class="member-signature"><span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>></span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1257">getAllScannersForTes [...]
+<div class="member-signature"><span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html" title="class or interface in java.util" class="external-link">List</a><<a href="KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a>></span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1255">getAllScannersForTes [...]
<div class="block">Used in testing.</div>
<dl class="notes">
<dt>Returns:</dt>
@@ -1530,20 +1530,20 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="enableLazySeekGlobally(boolean)">
<h3>enableLazySeekGlobally</h3>
-<div class="member-signature"><span class="modifiers">static</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1266">enableLazySeekGlobally</a></span><wbr><span class="parameters">(boolean enable)</span></div>
+<div class="member-signature"><span class="modifiers">static</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1264">enableLazySeekGlobally</a></span><wbr><span class="parameters">(boolean enable)</span></div>
</section>
</li>
<li>
<section class="detail" id="getEstimatedNumberOfKvsScanned()">
<h3>getEstimatedNumberOfKvsScanned</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">long</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1271">getEstimatedNumberOfKvsScanned</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">long</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1269">getEstimatedNumberOfKvsScanned</a></span>()</div>
<div class="block">Returns The estimated number of KVs seen by this scanner (includes some skipped KVs).</div>
</section>
</li>
<li>
<section class="detail" id="getNextIndexedKey()">
<h3>getNextIndexedKey</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type"><a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a></span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1275">getNextIndexedKey</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type"><a href="../ExtendedCell.html" title="interface in org.apache.hadoop.hbase">ExtendedCell</a></span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1273">getNextIndexedKey</a></span>()</div>
<dl class="notes">
<dt>Specified by:</dt>
<dd><code><a href="KeyValueScanner.html#getNextIndexedKey()">getNextIndexedKey</a></code> in interface <code><a href="KeyValueScanner.html" title="interface in org.apache.hadoop.hbase.regionserver">KeyValueScanner</a></code></dd>
@@ -1559,7 +1559,7 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<li>
<section class="detail" id="shipped()">
<h3>shipped</h3>
-<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1280">shipped</a></span>()
+<div class="member-signature"><span class="modifiers">public</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1278">shipped</a></span>()
throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/IOException.html" title="class or interface in java.io" class="external-link">IOException</a></span></div>
<div class="block"><span class="descfrm-type-label">Description copied from interface: <code><a href="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
@@ -1578,35 +1578,35 @@ implements <a href="KeyValueScanner.html" title="interface in org.apache.hadoop.
<section class="detail" id="instrument()">
<h3>instrument</h3>
<div class="member-signature"><span class="annotations">@LimitedPrivate("Unittest")
-</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1305">instrument</a></span>()</div>
+</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1303">instrument</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="hasUpdatedReaders()">
<h3>hasUpdatedReaders</h3>
<div class="member-signature"><span class="annotations">@LimitedPrivate("Unittest")
-</span><span class="modifiers">static final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1311">hasUpdatedReaders</a></span>()</div>
+</span><span class="modifiers">static final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1309">hasUpdatedReaders</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="hasSwitchedToStreamRead()">
<h3>hasSwitchedToStreamRead</h3>
<div class="member-signature"><span class="annotations">@LimitedPrivate("Unittest")
-</span><span class="modifiers">static final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1316">hasSwitchedToStreamRead</a></span>()</div>
+</span><span class="modifiers">static final</span> <span class="return-type">boolean</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1314">hasSwitchedToStreamRead</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="resetHasUpdatedReaders()">
<h3>resetHasUpdatedReaders</h3>
<div class="member-signature"><span class="annotations">@LimitedPrivate("Unittest")
-</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1321">resetHasUpdatedReaders</a></span>()</div>
+</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1319">resetHasUpdatedReaders</a></span>()</div>
</section>
</li>
<li>
<section class="detail" id="resetHasSwitchedToStreamRead()">
<h3>resetHasSwitchedToStreamRead</h3>
<div class="member-signature"><span class="annotations">@LimitedPrivate("Unittest")
-</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1326">resetHasSwitchedToStreamRead</a></span>()</div>
+</span><span class="modifiers">static final</span> <span class="return-type">void</span> <span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html#line-1324">resetHasSwitchedToStreamRead</a></span>()</div>
</section>
</li>
</ul>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
index 4bcf5fa6220..3c845fd720d 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/StoreScanner.html
@@ -977,370 +977,368 @@
<span class="source-line-no">964</span><span id="line-964"> } while ((nextCell = this.heap.peek()) != null && CellUtil.matchingRowColumn(cell, nextCell));</span>
<span class="source-line-no">965</span><span id="line-965"> // We need this check because it may happen that the new scanner that we get</span>
<span class="source-line-no">966</span><span id="line-966"> // during heap.next() is requiring reseek due of fake KV previously generated for</span>
-<span class="source-line-no">967</span><span id="line-967"> // ROWCOL bloom filter optimization. See HBASE-19863 for more details</span>
-<span class="source-line-no">968</span><span id="line-968"> if (</span>
-<span class="source-line-no">969</span><span id="line-969"> useRowColBloom && nextCell != null && cell.getTimestamp() == PrivateConstants.OLDEST_TIMESTAMP</span>
-<span class="source-line-no">970</span><span id="line-970"> ) {</span>
-<span class="source-line-no">971</span><span id="line-971"> return false;</span>
-<span class="source-line-no">972</span><span id="line-972"> }</span>
-<span class="source-line-no">973</span><span id="line-973"> return true;</span>
-<span class="source-line-no">974</span><span id="line-974"> }</span>
-<span class="source-line-no">975</span><span id="line-975"></span>
-<span class="source-line-no">976</span><span id="line-976"> @Override</span>
-<span class="source-line-no">977</span><span id="line-977"> public long getReadPoint() {</span>
-<span class="source-line-no">978</span><span id="line-978"> return this.readPt;</span>
-<span class="source-line-no">979</span><span id="line-979"> }</span>
-<span class="source-line-no">980</span><span id="line-980"></span>
-<span class="source-line-no">981</span><span id="line-981"> private static void clearAndClose(List<KeyValueScanner> scanners) {</span>
-<span class="source-line-no">982</span><span id="line-982"> if (scanners == null) {</span>
-<span class="source-line-no">983</span><span id="line-983"> return;</span>
-<span class="source-line-no">984</span><span id="line-984"> }</span>
-<span class="source-line-no">985</span><span id="line-985"> for (KeyValueScanner s : scanners) {</span>
-<span class="source-line-no">986</span><span id="line-986"> s.close();</span>
-<span class="source-line-no">987</span><span id="line-987"> }</span>
-<span class="source-line-no">988</span><span id="line-988"> scanners.clear();</span>
-<span class="source-line-no">989</span><span id="line-989"> }</span>
-<span class="source-line-no">990</span><span id="line-990"></span>
-<span class="source-line-no">991</span><span id="line-991"> // Implementation of ChangedReadersObserver</span>
-<span class="source-line-no">992</span><span id="line-992"> @Override</span>
-<span class="source-line-no">993</span><span id="line-993"> public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreScanners)</span>
-<span class="source-line-no">994</span><span id="line-994"> throws IOException {</span>
-<span class="source-line-no">995</span><span id="line-995"> if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {</span>
-<span class="source-line-no">996</span><span id="line-996"> return;</span>
-<span class="source-line-no">997</span><span id="line-997"> }</span>
-<span class="source-line-no">998</span><span id="line-998"> boolean updateReaders = false;</span>
-<span class="source-line-no">999</span><span id="line-999"> flushLock.lock();</span>
-<span class="source-line-no">1000</span><span id="line-1000"> try {</span>
-<span class="source-line-no">1001</span><span id="line-1001"> if (!closeLock.tryLock()) {</span>
-<span class="source-line-no">1002</span><span id="line-1002"> // The reason for doing this is that when the current store scanner does not retrieve</span>
-<span class="source-line-no">1003</span><span id="line-1003"> // any new cells, then the scanner is considered to be done. The heap of this scanner</span>
-<span class="source-line-no">1004</span><span id="line-1004"> // is not closed till the shipped() call is completed. Hence in that case if at all</span>
-<span class="source-line-no">1005</span><span id="line-1005"> // the partial close (close (false)) has been called before updateReaders(), there is no</span>
-<span class="source-line-no">1006</span><span id="line-1006"> // need for the updateReaders() to happen.</span>
-<span class="source-line-no">1007</span><span id="line-1007"> LOG.debug("StoreScanner already has the close lock. There is no need to updateReaders");</span>
-<span class="source-line-no">1008</span><span id="line-1008"> // no lock acquired.</span>
-<span class="source-line-no">1009</span><span id="line-1009"> clearAndClose(memStoreScanners);</span>
-<span class="source-line-no">1010</span><span id="line-1010"> return;</span>
-<span class="source-line-no">1011</span><span id="line-1011"> }</span>
-<span class="source-line-no">1012</span><span id="line-1012"> // lock acquired</span>
-<span class="source-line-no">1013</span><span id="line-1013"> updateReaders = true;</span>
-<span class="source-line-no">1014</span><span id="line-1014"> if (this.closing) {</span>
-<span class="source-line-no">1015</span><span id="line-1015"> LOG.debug("StoreScanner already closing. There is no need to updateReaders");</span>
-<span class="source-line-no">1016</span><span id="line-1016"> clearAndClose(memStoreScanners);</span>
-<span class="source-line-no">1017</span><span id="line-1017"> return;</span>
-<span class="source-line-no">1018</span><span id="line-1018"> }</span>
-<span class="source-line-no">1019</span><span id="line-1019"> flushed = true;</span>
-<span class="source-line-no">1020</span><span id="line-1020"> final boolean isCompaction = false;</span>
-<span class="source-line-no">1021</span><span id="line-1021"> boolean usePread = get || scanUsePread;</span>
-<span class="source-line-no">1022</span><span id="line-1022"> // SEE HBASE-19468 where the flushed files are getting compacted even before a scanner</span>
-<span class="source-line-no">1023</span><span id="line-1023"> // calls next(). So its better we create scanners here rather than next() call. Ensure</span>
-<span class="source-line-no">1024</span><span id="line-1024"> // these scanners are properly closed() whether or not the scan is completed successfully</span>
-<span class="source-line-no">1025</span><span id="line-1025"> // Eagerly creating scanners so that we have the ref counting ticking on the newly created</span>
-<span class="source-line-no">1026</span><span id="line-1026"> // store files. In case of stream scanners this eager creation does not induce performance</span>
-<span class="source-line-no">1027</span><span id="line-1027"> // penalty because in scans (that uses stream scanners) the next() call is bound to happen.</span>
-<span class="source-line-no">1028</span><span id="line-1028"> List<KeyValueScanner> scanners =</span>
-<span class="source-line-no">1029</span><span id="line-1029"> store.getScanners(sfs, cacheBlocks, get, usePread, isCompaction, matcher,</span>
-<span class="source-line-no">1030</span><span id="line-1030"> scan.getStartRow(), scan.getStopRow(), this.readPt, false, isOnlyLatestVersionScan(scan));</span>
-<span class="source-line-no">1031</span><span id="line-1031"> flushedstoreFileScanners.addAll(scanners);</span>
-<span class="source-line-no">1032</span><span id="line-1032"> if (!CollectionUtils.isEmpty(memStoreScanners)) {</span>
-<span class="source-line-no">1033</span><span id="line-1033"> clearAndClose(memStoreScannersAfterFlush);</span>
-<span class="source-line-no">1034</span><span id="line-1034"> memStoreScannersAfterFlush.addAll(memStoreScanners);</span>
-<span class="source-line-no">1035</span><span id="line-1035"> }</span>
-<span class="source-line-no">1036</span><span id="line-1036"> } finally {</span>
-<span class="source-line-no">1037</span><span id="line-1037"> flushLock.unlock();</span>
-<span class="source-line-no">1038</span><span id="line-1038"> if (updateReaders) {</span>
-<span class="source-line-no">1039</span><span id="line-1039"> closeLock.unlock();</span>
-<span class="source-line-no">1040</span><span id="line-1040"> }</span>
-<span class="source-line-no">1041</span><span id="line-1041"> if (hasUpdatedReaders != null) {</span>
-<span class="source-line-no">1042</span><span id="line-1042"> hasUpdatedReaders.set(true);</span>
-<span class="source-line-no">1043</span><span id="line-1043"> }</span>
-<span class="source-line-no">1044</span><span id="line-1044"> }</span>
-<span class="source-line-no">1045</span><span id="line-1045"> // Let the next() call handle re-creating and seeking</span>
-<span class="source-line-no">1046</span><span id="line-1046"> }</span>
-<span class="source-line-no">1047</span><span id="line-1047"></span>
-<span class="source-line-no">1048</span><span id="line-1048"> /** Returns if top of heap has changed (and KeyValueHeap has to try the next KV) */</span>
-<span class="source-line-no">1049</span><span id="line-1049"> protected final boolean reopenAfterFlush() throws IOException {</span>
-<span class="source-line-no">1050</span><span id="line-1050"> // here we can make sure that we have a Store instance so no null check on store.</span>
-<span class="source-line-no">1051</span><span id="line-1051"> ExtendedCell lastTop = heap.peek();</span>
-<span class="source-line-no">1052</span><span id="line-1052"> // When we have the scan object, should we not pass it to getScanners() to get a limited set of</span>
-<span class="source-line-no">1053</span><span id="line-1053"> // scanners? We did so in the constructor and we could have done it now by storing the scan</span>
-<span class="source-line-no">1054</span><span id="line-1054"> // object from the constructor</span>
-<span class="source-line-no">1055</span><span id="line-1055"> List<KeyValueScanner> scanners;</span>
-<span class="source-line-no">1056</span><span id="line-1056"> flushLock.lock();</span>
-<span class="source-line-no">1057</span><span id="line-1057"> try {</span>
-<span class="source-line-no">1058</span><span id="line-1058"> List<KeyValueScanner> allScanners =</span>
-<span class="source-line-no">1059</span><span id="line-1059"> new ArrayList<>(flushedstoreFileScanners.size() + memStoreScannersAfterFlush.size());</span>
-<span class="source-line-no">1060</span><span id="line-1060"> allScanners.addAll(flushedstoreFileScanners);</span>
-<span class="source-line-no">1061</span><span id="line-1061"> allScanners.addAll(memStoreScannersAfterFlush);</span>
-<span class="source-line-no">1062</span><span id="line-1062"> scanners = selectScannersFrom(store, allScanners);</span>
-<span class="source-line-no">1063</span><span id="line-1063"> // Clear the current set of flushed store files scanners so that they don't get added again</span>
-<span class="source-line-no">1064</span><span id="line-1064"> flushedstoreFileScanners.clear();</span>
-<span class="source-line-no">1065</span><span id="line-1065"> memStoreScannersAfterFlush.clear();</span>
-<span class="source-line-no">1066</span><span id="line-1066"> } finally {</span>
-<span class="source-line-no">1067</span><span id="line-1067"> flushLock.unlock();</span>
-<span class="source-line-no">1068</span><span id="line-1068"> }</span>
-<span class="source-line-no">1069</span><span id="line-1069"></span>
-<span class="source-line-no">1070</span><span id="line-1070"> // Seek the new scanners to the last key</span>
-<span class="source-line-no">1071</span><span id="line-1071"> seekScanners(scanners, lastTop, false, parallelSeekEnabled);</span>
-<span class="source-line-no">1072</span><span id="line-1072"> // remove the older memstore scanner</span>
-<span class="source-line-no">1073</span><span id="line-1073"> for (int i = currentScanners.size() - 1; i >= 0; i--) {</span>
-<span class="source-line-no">1074</span><span id="line-1074"> if (!currentScanners.get(i).isFileScanner()) {</span>
-<span class="source-line-no">1075</span><span id="line-1075"> scannersForDelayedClose.add(currentScanners.remove(i));</span>
-<span class="source-line-no">1076</span><span id="line-1076"> } else {</span>
-<span class="source-line-no">1077</span><span id="line-1077"> // we add the memstore scanner to the end of currentScanners</span>
-<span class="source-line-no">1078</span><span id="line-1078"> break;</span>
-<span class="source-line-no">1079</span><span id="line-1079"> }</span>
-<span class="source-line-no">1080</span><span id="line-1080"> }</span>
-<span class="source-line-no">1081</span><span id="line-1081"> // add the newly created scanners on the flushed files and the current active memstore scanner</span>
-<span class="source-line-no">1082</span><span id="line-1082"> addCurrentScanners(scanners);</span>
-<span class="source-line-no">1083</span><span id="line-1083"> // Combine all seeked scanners with a heap</span>
-<span class="source-line-no">1084</span><span id="line-1084"> resetKVHeap(this.currentScanners, store.getComparator());</span>
-<span class="source-line-no">1085</span><span id="line-1085"> resetQueryMatcher(lastTop);</span>
-<span class="source-line-no">1086</span><span id="line-1086"> if (heap.peek() == null || store.getComparator().compareRows(lastTop, this.heap.peek()) != 0) {</span>
-<span class="source-line-no">1087</span><span id="line-1087"> LOG.info("Storescanner.peek() is changed where before = " + lastTop.toString()</span>
-<span class="source-line-no">1088</span><span id="line-1088"> + ",and after = " + heap.peek());</span>
-<span class="source-line-no">1089</span><span id="line-1089"> topChanged = true;</span>
-<span class="source-line-no">1090</span><span id="line-1090"> } else {</span>
-<span class="source-line-no">1091</span><span id="line-1091"> topChanged = false;</span>
-<span class="source-line-no">1092</span><span id="line-1092"> }</span>
-<span class="source-line-no">1093</span><span id="line-1093"> return topChanged;</span>
-<span class="source-line-no">1094</span><span id="line-1094"> }</span>
-<span class="source-line-no">1095</span><span id="line-1095"></span>
-<span class="source-line-no">1096</span><span id="line-1096"> private void resetQueryMatcher(ExtendedCell lastTopKey) {</span>
-<span class="source-line-no">1097</span><span id="line-1097"> // Reset the state of the Query Matcher and set to top row.</span>
-<span class="source-line-no">1098</span><span id="line-1098"> // Only reset and call setRow if the row changes; avoids confusing the</span>
-<span class="source-line-no">1099</span><span id="line-1099"> // query matcher if scanning intra-row.</span>
-<span class="source-line-no">1100</span><span id="line-1100"> ExtendedCell cell = heap.peek();</span>
-<span class="source-line-no">1101</span><span id="line-1101"> if (cell == null) {</span>
-<span class="source-line-no">1102</span><span id="line-1102"> cell = lastTopKey;</span>
-<span class="source-line-no">1103</span><span id="line-1103"> }</span>
-<span class="source-line-no">1104</span><span id="line-1104"> if ((matcher.currentRow() == null) || !CellUtil.matchingRows(cell, matcher.currentRow())) {</span>
-<span class="source-line-no">1105</span><span id="line-1105"> this.countPerRow = 0;</span>
-<span class="source-line-no">1106</span><span id="line-1106"> // The setToNewRow will call reset internally</span>
-<span class="source-line-no">1107</span><span id="line-1107"> matcher.setToNewRow(cell);</span>
-<span class="source-line-no">1108</span><span id="line-1108"> }</span>
-<span class="source-line-no">1109</span><span id="line-1109"> }</span>
-<span class="source-line-no">1110</span><span id="line-1110"></span>
-<span class="source-line-no">1111</span><span id="line-1111"> /**</span>
-<span class="source-line-no">1112</span><span id="line-1112"> * Check whether scan as expected order</span>
-<span class="source-line-no">1113</span><span id="line-1113"> */</span>
-<span class="source-line-no">1114</span><span id="line-1114"> protected void checkScanOrder(Cell prevKV, Cell kv, CellComparator comparator)</span>
-<span class="source-line-no">1115</span><span id="line-1115"> throws IOException {</span>
-<span class="source-line-no">1116</span><span id="line-1116"> // Check that the heap gives us KVs in an increasing order.</span>
-<span class="source-line-no">1117</span><span id="line-1117"> assert prevKV == null || comparator == null || comparator.compare(prevKV, kv) <= 0</span>
-<span class="source-line-no">1118</span><span id="line-1118"> : "Key " + prevKV + " followed by a smaller key " + kv + " in cf " + store;</span>
-<span class="source-line-no">1119</span><span id="line-1119"> }</span>
-<span class="source-line-no">1120</span><span id="line-1120"></span>
-<span class="source-line-no">1121</span><span id="line-1121"> protected boolean seekToNextRow(ExtendedCell c) throws IOException {</span>
-<span class="source-line-no">1122</span><span id="line-1122"> return reseek(PrivateCellUtil.createLastOnRow(c));</span>
-<span class="source-line-no">1123</span><span id="line-1123"> }</span>
-<span class="source-line-no">1124</span><span id="line-1124"></span>
-<span class="source-line-no">1125</span><span id="line-1125"> /**</span>
-<span class="source-line-no">1126</span><span id="line-1126"> * Do a reseek in a normal StoreScanner(scan forward)</span>
-<span class="source-line-no">1127</span><span id="line-1127"> * @return true if scanner has values left, false if end of scanner</span>
-<span class="source-line-no">1128</span><span id="line-1128"> */</span>
-<span class="source-line-no">1129</span><span id="line-1129"> protected boolean seekAsDirection(ExtendedCell kv) throws IOException {</span>
-<span class="source-line-no">1130</span><span id="line-1130"> return reseek(kv);</span>
-<span class="source-line-no">1131</span><span id="line-1131"> }</span>
-<span class="source-line-no">1132</span><span id="line-1132"></span>
-<span class="source-line-no">1133</span><span id="line-1133"> @Override</span>
-<span class="source-line-no">1134</span><span id="line-1134"> public boolean reseek(ExtendedCell kv) throws IOException {</span>
-<span class="source-line-no">1135</span><span id="line-1135"> if (checkFlushed()) {</span>
-<span class="source-line-no">1136</span><span id="line-1136"> reopenAfterFlush();</span>
-<span class="source-line-no">1137</span><span id="line-1137"> }</span>
-<span class="source-line-no">1138</span><span id="line-1138"> if (explicitColumnQuery && lazySeekEnabledGlobally) {</span>
-<span class="source-line-no">1139</span><span id="line-1139"> return heap.requestSeek(kv, true, useRowColBloom);</span>
-<span class="source-line-no">1140</span><span id="line-1140"> }</span>
-<span class="source-line-no">1141</span><span id="line-1141"> return heap.reseek(kv);</span>
-<span class="source-line-no">1142</span><span id="line-1142"> }</span>
-<span class="source-line-no">1143</span><span id="line-1143"></span>
-<span class="source-line-no">1144</span><span id="line-1144"> void trySwitchToStreamRead() {</span>
-<span class="source-line-no">1145</span><span id="line-1145"> if (</span>
-<span class="source-line-no">1146</span><span id="line-1146"> readType != Scan.ReadType.DEFAULT || !scanUsePread || closing || heap.peek() == null</span>
-<span class="source-line-no">1147</span><span id="line-1147"> || bytesRead < preadMaxBytes</span>
-<span class="source-line-no">1148</span><span id="line-1148"> ) {</span>
-<span class="source-line-no">1149</span><span id="line-1149"> return;</span>
-<span class="source-line-no">1150</span><span id="line-1150"> }</span>
-<span class="source-line-no">1151</span><span id="line-1151"> LOG.debug("Switch to stream read (scanned={} bytes) of {}", bytesRead,</span>
-<span class="source-line-no">1152</span><span id="line-1152"> this.store.getColumnFamilyName());</span>
-<span class="source-line-no">1153</span><span id="line-1153"> scanUsePread = false;</span>
-<span class="source-line-no">1154</span><span id="line-1154"> ExtendedCell lastTop = heap.peek();</span>
-<span class="source-line-no">1155</span><span id="line-1155"> List<KeyValueScanner> memstoreScanners = new ArrayList<>();</span>
-<span class="source-line-no">1156</span><span id="line-1156"> List<KeyValueScanner> scannersToClose = new ArrayList<>();</span>
-<span class="source-line-no">1157</span><span id="line-1157"> for (KeyValueScanner kvs : currentScanners) {</span>
-<span class="source-line-no">1158</span><span id="line-1158"> if (!kvs.isFileScanner()) {</span>
-<span class="source-line-no">1159</span><span id="line-1159"> // collect memstorescanners here</span>
-<span class="source-line-no">1160</span><span id="line-1160"> memstoreScanners.add(kvs);</span>
-<span class="source-line-no">1161</span><span id="line-1161"> } else {</span>
-<span class="source-line-no">1162</span><span id="line-1162"> scannersToClose.add(kvs);</span>
-<span class="source-line-no">1163</span><span id="line-1163"> }</span>
-<span class="source-line-no">1164</span><span id="line-1164"> }</span>
-<span class="source-line-no">1165</span><span id="line-1165"> List<KeyValueScanner> fileScanners = null;</span>
-<span class="source-line-no">1166</span><span id="line-1166"> List<KeyValueScanner> newCurrentScanners;</span>
-<span class="source-line-no">1167</span><span id="line-1167"> KeyValueHeap newHeap;</span>
-<span class="source-line-no">1168</span><span id="line-1168"> try {</span>
-<span class="source-line-no">1169</span><span id="line-1169"> // We must have a store instance here so no null check</span>
-<span class="source-line-no">1170</span><span id="line-1170"> // recreate the scanners on the current file scanners</span>
-<span class="source-line-no">1171</span><span id="line-1171"> fileScanners = store.recreateScanners(scannersToClose, cacheBlocks, false, false, matcher,</span>
-<span class="source-line-no">1172</span><span id="line-1172"> scan.getStartRow(), scan.includeStartRow(), scan.getStopRow(), scan.includeStopRow(),</span>
-<span class="source-line-no">1173</span><span id="line-1173"> readPt, false);</span>
-<span class="source-line-no">1174</span><span id="line-1174"> if (fileScanners == null) {</span>
-<span class="source-line-no">1175</span><span id="line-1175"> return;</span>
-<span class="source-line-no">1176</span><span id="line-1176"> }</span>
-<span class="source-line-no">1177</span><span id="line-1177"> seekScanners(fileScanners, lastTop, false, parallelSeekEnabled);</span>
-<span class="source-line-no">1178</span><span id="line-1178"> newCurrentScanners = new ArrayList<>(fileScanners.size() + memstoreScanners.size());</span>
-<span class="source-line-no">1179</span><span id="line-1179"> newCurrentScanners.addAll(fileScanners);</span>
-<span class="source-line-no">1180</span><span id="line-1180"> newCurrentScanners.addAll(memstoreScanners);</span>
-<span class="source-line-no">1181</span><span id="line-1181"> newHeap = newKVHeap(newCurrentScanners, comparator);</span>
-<span class="source-line-no">1182</span><span id="line-1182"> } catch (Exception e) {</span>
-<span class="source-line-no">1183</span><span id="line-1183"> LOG.warn("failed to switch to stream read", e);</span>
-<span class="source-line-no">1184</span><span id="line-1184"> if (fileScanners != null) {</span>
-<span class="source-line-no">1185</span><span id="line-1185"> fileScanners.forEach(KeyValueScanner::close);</span>
-<span class="source-line-no">1186</span><span id="line-1186"> }</span>
-<span class="source-line-no">1187</span><span id="line-1187"> return;</span>
-<span class="source-line-no">1188</span><span id="line-1188"> }</span>
-<span class="source-line-no">1189</span><span id="line-1189"> currentScanners.clear();</span>
-<span class="source-line-no">1190</span><span id="line-1190"> addCurrentScanners(newCurrentScanners);</span>
-<span class="source-line-no">1191</span><span id="line-1191"> this.heap = newHeap;</span>
-<span class="source-line-no">1192</span><span id="line-1192"> resetQueryMatcher(lastTop);</span>
-<span class="source-line-no">1193</span><span id="line-1193"> scannersToClose.forEach(KeyValueScanner::close);</span>
-<span class="source-line-no">1194</span><span id="line-1194"> if (hasSwitchedToStreamRead != null) {</span>
-<span class="source-line-no">1195</span><span id="line-1195"> hasSwitchedToStreamRead.set(true);</span>
-<span class="source-line-no">1196</span><span id="line-1196"> }</span>
-<span class="source-line-no">1197</span><span id="line-1197"> }</span>
-<span class="source-line-no">1198</span><span id="line-1198"></span>
-<span class="source-line-no">1199</span><span id="line-1199"> protected final boolean checkFlushed() {</span>
-<span class="source-line-no">1200</span><span id="line-1200"> // check the var without any lock. Suppose even if we see the old</span>
-<span class="source-line-no">1201</span><span id="line-1201"> // value here still it is ok to continue because we will not be resetting</span>
-<span class="source-line-no">1202</span><span id="line-1202"> // the heap but will continue with the referenced memstore's snapshot. For compactions</span>
-<span class="source-line-no">1203</span><span id="line-1203"> // any way we don't need the updateReaders at all to happen as we still continue with</span>
-<span class="source-line-no">1204</span><span id="line-1204"> // the older files</span>
-<span class="source-line-no">1205</span><span id="line-1205"> if (flushed) {</span>
-<span class="source-line-no">1206</span><span id="line-1206"> // If there is a flush and the current scan is notified on the flush ensure that the</span>
-<span class="source-line-no">1207</span><span id="line-1207"> // scan's heap gets reset and we do a seek on the newly flushed file.</span>
-<span class="source-line-no">1208</span><span id="line-1208"> if (this.closing) {</span>
-<span class="source-line-no">1209</span><span id="line-1209"> return false;</span>
-<span class="source-line-no">1210</span><span id="line-1210"> }</span>
-<span class="source-line-no">1211</span><span id="line-1211"> // reset the flag</span>
-<span class="source-line-no">1212</span><span id="line-1212"> flushed = false;</span>
-<span class="source-line-no">1213</span><span id="line-1213"> return true;</span>
-<span class="source-line-no">1214</span><span id="line-1214"> }</span>
-<span class="source-line-no">1215</span><span id="line-1215"> return false;</span>
-<span class="source-line-no">1216</span><span id="line-1216"> }</span>
-<span class="source-line-no">1217</span><span id="line-1217"></span>
-<span class="source-line-no">1218</span><span id="line-1218"> /**</span>
-<span class="source-line-no">1219</span><span id="line-1219"> * Seek storefiles in parallel to optimize IO latency as much as possible</span>
-<span class="source-line-no">1220</span><span id="line-1220"> * @param scanners the list {@link KeyValueScanner}s to be read from</span>
-<span class="source-line-no">1221</span><span id="line-1221"> * @param kv the KeyValue on which the operation is being requested</span>
-<span class="source-line-no">1222</span><span id="line-1222"> */</span>
-<span class="source-line-no">1223</span><span id="line-1223"> private void parallelSeek(final List<? extends KeyValueScanner> scanners, final ExtendedCell kv)</span>
-<span class="source-line-no">1224</span><span id="line-1224"> throws IOException {</span>
-<span class="source-line-no">1225</span><span id="line-1225"> if (scanners.isEmpty()) return;</span>
-<span class="source-line-no">1226</span><span id="line-1226"> int storeFileScannerCount = scanners.size();</span>
-<span class="source-line-no">1227</span><span id="line-1227"> CountDownLatch latch = new CountDownLatch(storeFileScannerCount);</span>
-<span class="source-line-no">1228</span><span id="line-1228"> List<ParallelSeekHandler> handlers = new ArrayList<>(storeFileScannerCount);</span>
-<span class="source-line-no">1229</span><span id="line-1229"> for (KeyValueScanner scanner : scanners) {</span>
-<span class="source-line-no">1230</span><span id="line-1230"> if (scanner instanceof StoreFileScanner) {</span>
-<span class="source-line-no">1231</span><span id="line-1231"> ParallelSeekHandler seekHandler = new ParallelSeekHandler(scanner, kv, this.readPt, latch);</span>
-<span class="source-line-no">1232</span><span id="line-1232"> executor.submit(seekHandler);</span>
-<span class="source-line-no">1233</span><span id="line-1233"> handlers.add(seekHandler);</span>
-<span class="source-line-no">1234</span><span id="line-1234"> } else {</span>
-<span class="source-line-no">1235</span><span id="line-1235"> scanner.seek(kv);</span>
-<span class="source-line-no">1236</span><span id="line-1236"> latch.countDown();</span>
-<span class="source-line-no">1237</span><span id="line-1237"> }</span>
-<span class="source-line-no">1238</span><span id="line-1238"> }</span>
-<span class="source-line-no">1239</span><span id="line-1239"></span>
-<span class="source-line-no">1240</span><span id="line-1240"> try {</span>
-<span class="source-line-no">1241</span><span id="line-1241"> latch.await();</span>
-<span class="source-line-no">1242</span><span id="line-1242"> } catch (InterruptedException ie) {</span>
-<span class="source-line-no">1243</span><span id="line-1243"> throw (InterruptedIOException) new InterruptedIOException().initCause(ie);</span>
-<span class="source-line-no">1244</span><span id="line-1244"> }</span>
-<span class="source-line-no">1245</span><span id="line-1245"></span>
-<span class="source-line-no">1246</span><span id="line-1246"> for (ParallelSeekHandler handler : handlers) {</span>
-<span class="source-line-no">1247</span><span id="line-1247"> if (handler.getErr() != null) {</span>
-<span class="source-line-no">1248</span><span id="line-1248"> throw new IOException(handler.getErr());</span>
-<span class="source-line-no">1249</span><span id="line-1249"> }</span>
-<span class="source-line-no">1250</span><span id="line-1250"> }</span>
-<span class="source-line-no">1251</span><span id="line-1251"> }</span>
-<span class="source-line-no">1252</span><span id="line-1252"></span>
-<span class="source-line-no">1253</span><span id="line-1253"> /**</span>
-<span class="source-line-no">1254</span><span id="line-1254"> * Used in testing.</span>
-<span class="source-line-no">1255</span><span id="line-1255"> * @return all scanners in no particular order</span>
-<span class="source-line-no">1256</span><span id="line-1256"> */</span>
-<span class="source-line-no">1257</span><span id="line-1257"> List<KeyValueScanner> getAllScannersForTesting() {</span>
-<span class="source-line-no">1258</span><span id="line-1258"> List<KeyValueScanner> allScanners = new ArrayList<>();</span>
-<span class="source-line-no">1259</span><span id="line-1259"> KeyValueScanner current = heap.getCurrentForTesting();</span>
-<span class="source-line-no">1260</span><span id="line-1260"> if (current != null) allScanners.add(current);</span>
-<span class="source-line-no">1261</span><span id="line-1261"> for (KeyValueScanner scanner : heap.getHeap())</span>
-<span class="source-line-no">1262</span><span id="line-1262"> allScanners.add(scanner);</span>
-<span class="source-line-no">1263</span><span id="line-1263"> return allScanners;</span>
-<span class="source-line-no">1264</span><span id="line-1264"> }</span>
-<span class="source-line-no">1265</span><span id="line-1265"></span>
-<span class="source-line-no">1266</span><span id="line-1266"> static void enableLazySeekGlobally(boolean enable) {</span>
-<span class="source-line-no">1267</span><span id="line-1267"> lazySeekEnabledGlobally = enable;</span>
-<span class="source-line-no">1268</span><span id="line-1268"> }</span>
-<span class="source-line-no">1269</span><span id="line-1269"></span>
-<span class="source-line-no">1270</span><span id="line-1270"> /** Returns The estimated number of KVs seen by this scanner (includes some skipped KVs). */</span>
-<span class="source-line-no">1271</span><span id="line-1271"> public long getEstimatedNumberOfKvsScanned() {</span>
-<span class="source-line-no">1272</span><span id="line-1272"> return this.kvsScanned;</span>
-<span class="source-line-no">1273</span><span id="line-1273"> }</span>
-<span class="source-line-no">1274</span><span id="line-1274"></span>
-<span class="source-line-no">1275</span><span id="line-1275"> @Override</span>
-<span class="source-line-no">1276</span><span id="line-1276"> public ExtendedCell getNextIndexedKey() {</span>
-<span class="source-line-no">1277</span><span id="line-1277"> return this.heap.getNextIndexedKey();</span>
-<span class="source-line-no">1278</span><span id="line-1278"> }</span>
-<span class="source-line-no">1279</span><span id="line-1279"></span>
-<span class="source-line-no">1280</span><span id="line-1280"> @Override</span>
-<span class="source-line-no">1281</span><span id="line-1281"> public void shipped() throws IOException {</span>
-<span class="source-line-no">1282</span><span id="line-1282"> if (prevCell != null) {</span>
-<span class="source-line-no">1283</span><span id="line-1283"> // Do the copy here so that in case the prevCell ref is pointing to the previous</span>
-<span class="source-line-no">1284</span><span id="line-1284"> // blocks we can safely release those blocks.</span>
-<span class="source-line-no">1285</span><span id="line-1285"> // This applies to blocks that are got from Bucket cache, L1 cache and the blocks</span>
-<span class="source-line-no">1286</span><span id="line-1286"> // fetched from HDFS. Copying this would ensure that we let go the references to these</span>
-<span class="source-line-no">1287</span><span id="line-1287"> // blocks so that they can be GCed safely(in case of bucket cache)</span>
-<span class="source-line-no">1288</span><span id="line-1288"> prevCell = KeyValueUtil.toNewKeyCell(this.prevCell);</span>
-<span class="source-line-no">1289</span><span id="line-1289"> }</span>
-<span class="source-line-no">1290</span><span id="line-1290"> matcher.beforeShipped();</span>
-<span class="source-line-no">1291</span><span id="line-1291"> // There wont be further fetch of Cells from these scanners. Just close.</span>
-<span class="source-line-no">1292</span><span id="line-1292"> clearAndClose(scannersForDelayedClose);</span>
-<span class="source-line-no">1293</span><span id="line-1293"> if (this.heap != null) {</span>
-<span class="source-line-no">1294</span><span id="line-1294"> this.heap.shipped();</span>
-<span class="source-line-no">1295</span><span id="line-1295"> // When switching from pread to stream, we will open a new scanner for each store file, but</span>
-<span class="source-line-no">1296</span><span id="line-1296"> // the old scanner may still track the HFileBlocks we have scanned but not sent back to client</span>
-<span class="source-line-no">1297</span><span id="line-1297"> // yet. If we close the scanner immediately then the HFileBlocks may be messed up by others</span>
-<span class="source-line-no">1298</span><span id="line-1298"> // before we serialize and send it back to client. The HFileBlocks will be released in shipped</span>
-<span class="source-line-no">1299</span><span id="line-1299"> // method, so we here will also open new scanners and close old scanners in shipped method.</span>
-<span class="source-line-no">1300</span><span id="line-1300"> // See HBASE-18055 for more details.</span>
-<span class="source-line-no">1301</span><span id="line-1301"> trySwitchToStreamRead();</span>
-<span class="source-line-no">1302</span><span id="line-1302"> }</span>
-<span class="source-line-no">1303</span><span id="line-1303"> }</span>
-<span class="source-line-no">1304</span><span id="line-1304"></span>
-<span class="source-line-no">1305</span><span id="line-1305"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1306</span><span id="line-1306"> static final void instrument() {</span>
-<span class="source-line-no">1307</span><span id="line-1307"> hasUpdatedReaders = new AtomicBoolean(false);</span>
-<span class="source-line-no">1308</span><span id="line-1308"> hasSwitchedToStreamRead = new AtomicBoolean(false);</span>
-<span class="source-line-no">1309</span><span id="line-1309"> }</span>
-<span class="source-line-no">1310</span><span id="line-1310"></span>
-<span class="source-line-no">1311</span><span id="line-1311"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1312</span><span id="line-1312"> static final boolean hasUpdatedReaders() {</span>
-<span class="source-line-no">1313</span><span id="line-1313"> return hasUpdatedReaders.get();</span>
-<span class="source-line-no">1314</span><span id="line-1314"> }</span>
-<span class="source-line-no">1315</span><span id="line-1315"></span>
-<span class="source-line-no">1316</span><span id="line-1316"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1317</span><span id="line-1317"> static final boolean hasSwitchedToStreamRead() {</span>
-<span class="source-line-no">1318</span><span id="line-1318"> return hasSwitchedToStreamRead.get();</span>
-<span class="source-line-no">1319</span><span id="line-1319"> }</span>
-<span class="source-line-no">1320</span><span id="line-1320"></span>
-<span class="source-line-no">1321</span><span id="line-1321"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1322</span><span id="line-1322"> static final void resetHasUpdatedReaders() {</span>
-<span class="source-line-no">1323</span><span id="line-1323"> hasUpdatedReaders.set(false);</span>
-<span class="source-line-no">1324</span><span id="line-1324"> }</span>
-<span class="source-line-no">1325</span><span id="line-1325"></span>
-<span class="source-line-no">1326</span><span id="line-1326"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
-<span class="source-line-no">1327</span><span id="line-1327"> static final void resetHasSwitchedToStreamRead() {</span>
-<span class="source-line-no">1328</span><span id="line-1328"> hasSwitchedToStreamRead.set(false);</span>
-<span class="source-line-no">1329</span><span id="line-1329"> }</span>
-<span class="source-line-no">1330</span><span id="line-1330">}</span>
+<span class="source-line-no">967</span><span id="line-967"> // ROWCOL bloom filter optimization. See HBASE-19863 and HBASE-29907 for more details</span>
+<span class="source-line-no">968</span><span id="line-968"> if (useRowColBloom && nextCell != null && matcher.compareKeyForNextColumn(nextCell, cell) < 0) {</span>
+<span class="source-line-no">969</span><span id="line-969"> return false;</span>
+<span class="source-line-no">970</span><span id="line-970"> }</span>
+<span class="source-line-no">971</span><span id="line-971"> return true;</span>
+<span class="source-line-no">972</span><span id="line-972"> }</span>
+<span class="source-line-no">973</span><span id="line-973"></span>
+<span class="source-line-no">974</span><span id="line-974"> @Override</span>
+<span class="source-line-no">975</span><span id="line-975"> public long getReadPoint() {</span>
+<span class="source-line-no">976</span><span id="line-976"> return this.readPt;</span>
+<span class="source-line-no">977</span><span id="line-977"> }</span>
+<span class="source-line-no">978</span><span id="line-978"></span>
+<span class="source-line-no">979</span><span id="line-979"> private static void clearAndClose(List<KeyValueScanner> scanners) {</span>
+<span class="source-line-no">980</span><span id="line-980"> if (scanners == null) {</span>
+<span class="source-line-no">981</span><span id="line-981"> return;</span>
+<span class="source-line-no">982</span><span id="line-982"> }</span>
+<span class="source-line-no">983</span><span id="line-983"> for (KeyValueScanner s : scanners) {</span>
+<span class="source-line-no">984</span><span id="line-984"> s.close();</span>
+<span class="source-line-no">985</span><span id="line-985"> }</span>
+<span class="source-line-no">986</span><span id="line-986"> scanners.clear();</span>
+<span class="source-line-no">987</span><span id="line-987"> }</span>
+<span class="source-line-no">988</span><span id="line-988"></span>
+<span class="source-line-no">989</span><span id="line-989"> // Implementation of ChangedReadersObserver</span>
+<span class="source-line-no">990</span><span id="line-990"> @Override</span>
+<span class="source-line-no">991</span><span id="line-991"> public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreScanners)</span>
+<span class="source-line-no">992</span><span id="line-992"> throws IOException {</span>
+<span class="source-line-no">993</span><span id="line-993"> if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {</span>
+<span class="source-line-no">994</span><span id="line-994"> return;</span>
+<span class="source-line-no">995</span><span id="line-995"> }</span>
+<span class="source-line-no">996</span><span id="line-996"> boolean updateReaders = false;</span>
+<span class="source-line-no">997</span><span id="line-997"> flushLock.lock();</span>
+<span class="source-line-no">998</span><span id="line-998"> try {</span>
+<span class="source-line-no">999</span><span id="line-999"> if (!closeLock.tryLock()) {</span>
+<span class="source-line-no">1000</span><span id="line-1000"> // The reason for doing this is that when the current store scanner does not retrieve</span>
+<span class="source-line-no">1001</span><span id="line-1001"> // any new cells, then the scanner is considered to be done. The heap of this scanner</span>
+<span class="source-line-no">1002</span><span id="line-1002"> // is not closed till the shipped() call is completed. Hence in that case if at all</span>
+<span class="source-line-no">1003</span><span id="line-1003"> // the partial close (close (false)) has been called before updateReaders(), there is no</span>
+<span class="source-line-no">1004</span><span id="line-1004"> // need for the updateReaders() to happen.</span>
+<span class="source-line-no">1005</span><span id="line-1005"> LOG.debug("StoreScanner already has the close lock. There is no need to updateReaders");</span>
+<span class="source-line-no">1006</span><span id="line-1006"> // no lock acquired.</span>
+<span class="source-line-no">1007</span><span id="line-1007"> clearAndClose(memStoreScanners);</span>
+<span class="source-line-no">1008</span><span id="line-1008"> return;</span>
+<span class="source-line-no">1009</span><span id="line-1009"> }</span>
+<span class="source-line-no">1010</span><span id="line-1010"> // lock acquired</span>
+<span class="source-line-no">1011</span><span id="line-1011"> updateReaders = true;</span>
+<span class="source-line-no">1012</span><span id="line-1012"> if (this.closing) {</span>
+<span class="source-line-no">1013</span><span id="line-1013"> LOG.debug("StoreScanner already closing. There is no need to updateReaders");</span>
+<span class="source-line-no">1014</span><span id="line-1014"> clearAndClose(memStoreScanners);</span>
+<span class="source-line-no">1015</span><span id="line-1015"> return;</span>
+<span class="source-line-no">1016</span><span id="line-1016"> }</span>
+<span class="source-line-no">1017</span><span id="line-1017"> flushed = true;</span>
+<span class="source-line-no">1018</span><span id="line-1018"> final boolean isCompaction = false;</span>
+<span class="source-line-no">1019</span><span id="line-1019"> boolean usePread = get || scanUsePread;</span>
+<span class="source-line-no">1020</span><span id="line-1020"> // SEE HBASE-19468 where the flushed files are getting compacted even before a scanner</span>
+<span class="source-line-no">1021</span><span id="line-1021"> // calls next(). So its better we create scanners here rather than next() call. Ensure</span>
+<span class="source-line-no">1022</span><span id="line-1022"> // these scanners are properly closed() whether or not the scan is completed successfully</span>
+<span class="source-line-no">1023</span><span id="line-1023"> // Eagerly creating scanners so that we have the ref counting ticking on the newly created</span>
+<span class="source-line-no">1024</span><span id="line-1024"> // store files. In case of stream scanners this eager creation does not induce performance</span>
+<span class="source-line-no">1025</span><span id="line-1025"> // penalty because in scans (that uses stream scanners) the next() call is bound to happen.</span>
+<span class="source-line-no">1026</span><span id="line-1026"> List<KeyValueScanner> scanners =</span>
+<span class="source-line-no">1027</span><span id="line-1027"> store.getScanners(sfs, cacheBlocks, get, usePread, isCompaction, matcher,</span>
+<span class="source-line-no">1028</span><span id="line-1028"> scan.getStartRow(), scan.getStopRow(), this.readPt, false, isOnlyLatestVersionScan(scan));</span>
+<span class="source-line-no">1029</span><span id="line-1029"> flushedstoreFileScanners.addAll(scanners);</span>
+<span class="source-line-no">1030</span><span id="line-1030"> if (!CollectionUtils.isEmpty(memStoreScanners)) {</span>
+<span class="source-line-no">1031</span><span id="line-1031"> clearAndClose(memStoreScannersAfterFlush);</span>
+<span class="source-line-no">1032</span><span id="line-1032"> memStoreScannersAfterFlush.addAll(memStoreScanners);</span>
+<span class="source-line-no">1033</span><span id="line-1033"> }</span>
+<span class="source-line-no">1034</span><span id="line-1034"> } finally {</span>
+<span class="source-line-no">1035</span><span id="line-1035"> flushLock.unlock();</span>
+<span class="source-line-no">1036</span><span id="line-1036"> if (updateReaders) {</span>
+<span class="source-line-no">1037</span><span id="line-1037"> closeLock.unlock();</span>
+<span class="source-line-no">1038</span><span id="line-1038"> }</span>
+<span class="source-line-no">1039</span><span id="line-1039"> if (hasUpdatedReaders != null) {</span>
+<span class="source-line-no">1040</span><span id="line-1040"> hasUpdatedReaders.set(true);</span>
+<span class="source-line-no">1041</span><span id="line-1041"> }</span>
+<span class="source-line-no">1042</span><span id="line-1042"> }</span>
+<span class="source-line-no">1043</span><span id="line-1043"> // Let the next() call handle re-creating and seeking</span>
+<span class="source-line-no">1044</span><span id="line-1044"> }</span>
+<span class="source-line-no">1045</span><span id="line-1045"></span>
+<span class="source-line-no">1046</span><span id="line-1046"> /** Returns if top of heap has changed (and KeyValueHeap has to try the next KV) */</span>
+<span class="source-line-no">1047</span><span id="line-1047"> protected final boolean reopenAfterFlush() throws IOException {</span>
+<span class="source-line-no">1048</span><span id="line-1048"> // here we can make sure that we have a Store instance so no null check on store.</span>
+<span class="source-line-no">1049</span><span id="line-1049"> ExtendedCell lastTop = heap.peek();</span>
+<span class="source-line-no">1050</span><span id="line-1050"> // When we have the scan object, should we not pass it to getScanners() to get a limited set of</span>
+<span class="source-line-no">1051</span><span id="line-1051"> // scanners? We did so in the constructor and we could have done it now by storing the scan</span>
+<span class="source-line-no">1052</span><span id="line-1052"> // object from the constructor</span>
+<span class="source-line-no">1053</span><span id="line-1053"> List<KeyValueScanner> scanners;</span>
+<span class="source-line-no">1054</span><span id="line-1054"> flushLock.lock();</span>
+<span class="source-line-no">1055</span><span id="line-1055"> try {</span>
+<span class="source-line-no">1056</span><span id="line-1056"> List<KeyValueScanner> allScanners =</span>
+<span class="source-line-no">1057</span><span id="line-1057"> new ArrayList<>(flushedstoreFileScanners.size() + memStoreScannersAfterFlush.size());</span>
+<span class="source-line-no">1058</span><span id="line-1058"> allScanners.addAll(flushedstoreFileScanners);</span>
+<span class="source-line-no">1059</span><span id="line-1059"> allScanners.addAll(memStoreScannersAfterFlush);</span>
+<span class="source-line-no">1060</span><span id="line-1060"> scanners = selectScannersFrom(store, allScanners);</span>
+<span class="source-line-no">1061</span><span id="line-1061"> // Clear the current set of flushed store files scanners so that they don't get added again</span>
+<span class="source-line-no">1062</span><span id="line-1062"> flushedstoreFileScanners.clear();</span>
+<span class="source-line-no">1063</span><span id="line-1063"> memStoreScannersAfterFlush.clear();</span>
+<span class="source-line-no">1064</span><span id="line-1064"> } finally {</span>
+<span class="source-line-no">1065</span><span id="line-1065"> flushLock.unlock();</span>
+<span class="source-line-no">1066</span><span id="line-1066"> }</span>
+<span class="source-line-no">1067</span><span id="line-1067"></span>
+<span class="source-line-no">1068</span><span id="line-1068"> // Seek the new scanners to the last key</span>
+<span class="source-line-no">1069</span><span id="line-1069"> seekScanners(scanners, lastTop, false, parallelSeekEnabled);</span>
+<span class="source-line-no">1070</span><span id="line-1070"> // remove the older memstore scanner</span>
+<span class="source-line-no">1071</span><span id="line-1071"> for (int i = currentScanners.size() - 1; i >= 0; i--) {</span>
+<span class="source-line-no">1072</span><span id="line-1072"> if (!currentScanners.get(i).isFileScanner()) {</span>
+<span class="source-line-no">1073</span><span id="line-1073"> scannersForDelayedClose.add(currentScanners.remove(i));</span>
+<span class="source-line-no">1074</span><span id="line-1074"> } else {</span>
+<span class="source-line-no">1075</span><span id="line-1075"> // we add the memstore scanner to the end of currentScanners</span>
+<span class="source-line-no">1076</span><span id="line-1076"> break;</span>
+<span class="source-line-no">1077</span><span id="line-1077"> }</span>
+<span class="source-line-no">1078</span><span id="line-1078"> }</span>
+<span class="source-line-no">1079</span><span id="line-1079"> // add the newly created scanners on the flushed files and the current active memstore scanner</span>
+<span class="source-line-no">1080</span><span id="line-1080"> addCurrentScanners(scanners);</span>
+<span class="source-line-no">1081</span><span id="line-1081"> // Combine all seeked scanners with a heap</span>
+<span class="source-line-no">1082</span><span id="line-1082"> resetKVHeap(this.currentScanners, store.getComparator());</span>
+<span class="source-line-no">1083</span><span id="line-1083"> resetQueryMatcher(lastTop);</span>
+<span class="source-line-no">1084</span><span id="line-1084"> if (heap.peek() == null || store.getComparator().compareRows(lastTop, this.heap.peek()) != 0) {</span>
+<span class="source-line-no">1085</span><span id="line-1085"> LOG.info("Storescanner.peek() is changed where before = " + lastTop.toString()</span>
+<span class="source-line-no">1086</span><span id="line-1086"> + ",and after = " + heap.peek());</span>
+<span class="source-line-no">1087</span><span id="line-1087"> topChanged = true;</span>
+<span class="source-line-no">1088</span><span id="line-1088"> } else {</span>
+<span class="source-line-no">1089</span><span id="line-1089"> topChanged = false;</span>
+<span class="source-line-no">1090</span><span id="line-1090"> }</span>
+<span class="source-line-no">1091</span><span id="line-1091"> return topChanged;</span>
+<span class="source-line-no">1092</span><span id="line-1092"> }</span>
+<span class="source-line-no">1093</span><span id="line-1093"></span>
+<span class="source-line-no">1094</span><span id="line-1094"> private void resetQueryMatcher(ExtendedCell lastTopKey) {</span>
+<span class="source-line-no">1095</span><span id="line-1095"> // Reset the state of the Query Matcher and set to top row.</span>
+<span class="source-line-no">1096</span><span id="line-1096"> // Only reset and call setRow if the row changes; avoids confusing the</span>
+<span class="source-line-no">1097</span><span id="line-1097"> // query matcher if scanning intra-row.</span>
+<span class="source-line-no">1098</span><span id="line-1098"> ExtendedCell cell = heap.peek();</span>
+<span class="source-line-no">1099</span><span id="line-1099"> if (cell == null) {</span>
+<span class="source-line-no">1100</span><span id="line-1100"> cell = lastTopKey;</span>
+<span class="source-line-no">1101</span><span id="line-1101"> }</span>
+<span class="source-line-no">1102</span><span id="line-1102"> if ((matcher.currentRow() == null) || !CellUtil.matchingRows(cell, matcher.currentRow())) {</span>
+<span class="source-line-no">1103</span><span id="line-1103"> this.countPerRow = 0;</span>
+<span class="source-line-no">1104</span><span id="line-1104"> // The setToNewRow will call reset internally</span>
+<span class="source-line-no">1105</span><span id="line-1105"> matcher.setToNewRow(cell);</span>
+<span class="source-line-no">1106</span><span id="line-1106"> }</span>
+<span class="source-line-no">1107</span><span id="line-1107"> }</span>
+<span class="source-line-no">1108</span><span id="line-1108"></span>
+<span class="source-line-no">1109</span><span id="line-1109"> /**</span>
+<span class="source-line-no">1110</span><span id="line-1110"> * Check whether scan as expected order</span>
+<span class="source-line-no">1111</span><span id="line-1111"> */</span>
+<span class="source-line-no">1112</span><span id="line-1112"> protected void checkScanOrder(Cell prevKV, Cell kv, CellComparator comparator)</span>
+<span class="source-line-no">1113</span><span id="line-1113"> throws IOException {</span>
+<span class="source-line-no">1114</span><span id="line-1114"> // Check that the heap gives us KVs in an increasing order.</span>
+<span class="source-line-no">1115</span><span id="line-1115"> assert prevKV == null || comparator == null || comparator.compare(prevKV, kv) <= 0</span>
+<span class="source-line-no">1116</span><span id="line-1116"> : "Key " + prevKV + " followed by a smaller key " + kv + " in cf " + store;</span>
+<span class="source-line-no">1117</span><span id="line-1117"> }</span>
+<span class="source-line-no">1118</span><span id="line-1118"></span>
+<span class="source-line-no">1119</span><span id="line-1119"> protected boolean seekToNextRow(ExtendedCell c) throws IOException {</span>
+<span class="source-line-no">1120</span><span id="line-1120"> return reseek(PrivateCellUtil.createLastOnRow(c));</span>
+<span class="source-line-no">1121</span><span id="line-1121"> }</span>
+<span class="source-line-no">1122</span><span id="line-1122"></span>
+<span class="source-line-no">1123</span><span id="line-1123"> /**</span>
+<span class="source-line-no">1124</span><span id="line-1124"> * Do a reseek in a normal StoreScanner(scan forward)</span>
+<span class="source-line-no">1125</span><span id="line-1125"> * @return true if scanner has values left, false if end of scanner</span>
+<span class="source-line-no">1126</span><span id="line-1126"> */</span>
+<span class="source-line-no">1127</span><span id="line-1127"> protected boolean seekAsDirection(ExtendedCell kv) throws IOException {</span>
+<span class="source-line-no">1128</span><span id="line-1128"> return reseek(kv);</span>
+<span class="source-line-no">1129</span><span id="line-1129"> }</span>
+<span class="source-line-no">1130</span><span id="line-1130"></span>
+<span class="source-line-no">1131</span><span id="line-1131"> @Override</span>
+<span class="source-line-no">1132</span><span id="line-1132"> public boolean reseek(ExtendedCell kv) throws IOException {</span>
+<span class="source-line-no">1133</span><span id="line-1133"> if (checkFlushed()) {</span>
+<span class="source-line-no">1134</span><span id="line-1134"> reopenAfterFlush();</span>
+<span class="source-line-no">1135</span><span id="line-1135"> }</span>
+<span class="source-line-no">1136</span><span id="line-1136"> if (explicitColumnQuery && lazySeekEnabledGlobally) {</span>
+<span class="source-line-no">1137</span><span id="line-1137"> return heap.requestSeek(kv, true, useRowColBloom);</span>
+<span class="source-line-no">1138</span><span id="line-1138"> }</span>
+<span class="source-line-no">1139</span><span id="line-1139"> return heap.reseek(kv);</span>
+<span class="source-line-no">1140</span><span id="line-1140"> }</span>
+<span class="source-line-no">1141</span><span id="line-1141"></span>
+<span class="source-line-no">1142</span><span id="line-1142"> void trySwitchToStreamRead() {</span>
+<span class="source-line-no">1143</span><span id="line-1143"> if (</span>
+<span class="source-line-no">1144</span><span id="line-1144"> readType != Scan.ReadType.DEFAULT || !scanUsePread || closing || heap.peek() == null</span>
+<span class="source-line-no">1145</span><span id="line-1145"> || bytesRead < preadMaxBytes</span>
+<span class="source-line-no">1146</span><span id="line-1146"> ) {</span>
+<span class="source-line-no">1147</span><span id="line-1147"> return;</span>
+<span class="source-line-no">1148</span><span id="line-1148"> }</span>
+<span class="source-line-no">1149</span><span id="line-1149"> LOG.debug("Switch to stream read (scanned={} bytes) of {}", bytesRead,</span>
+<span class="source-line-no">1150</span><span id="line-1150"> this.store.getColumnFamilyName());</span>
+<span class="source-line-no">1151</span><span id="line-1151"> scanUsePread = false;</span>
+<span class="source-line-no">1152</span><span id="line-1152"> ExtendedCell lastTop = heap.peek();</span>
+<span class="source-line-no">1153</span><span id="line-1153"> List<KeyValueScanner> memstoreScanners = new ArrayList<>();</span>
+<span class="source-line-no">1154</span><span id="line-1154"> List<KeyValueScanner> scannersToClose = new ArrayList<>();</span>
+<span class="source-line-no">1155</span><span id="line-1155"> for (KeyValueScanner kvs : currentScanners) {</span>
+<span class="source-line-no">1156</span><span id="line-1156"> if (!kvs.isFileScanner()) {</span>
+<span class="source-line-no">1157</span><span id="line-1157"> // collect memstorescanners here</span>
+<span class="source-line-no">1158</span><span id="line-1158"> memstoreScanners.add(kvs);</span>
+<span class="source-line-no">1159</span><span id="line-1159"> } else {</span>
+<span class="source-line-no">1160</span><span id="line-1160"> scannersToClose.add(kvs);</span>
+<span class="source-line-no">1161</span><span id="line-1161"> }</span>
+<span class="source-line-no">1162</span><span id="line-1162"> }</span>
+<span class="source-line-no">1163</span><span id="line-1163"> List<KeyValueScanner> fileScanners = null;</span>
+<span class="source-line-no">1164</span><span id="line-1164"> List<KeyValueScanner> newCurrentScanners;</span>
+<span class="source-line-no">1165</span><span id="line-1165"> KeyValueHeap newHeap;</span>
+<span class="source-line-no">1166</span><span id="line-1166"> try {</span>
+<span class="source-line-no">1167</span><span id="line-1167"> // We must have a store instance here so no null check</span>
+<span class="source-line-no">1168</span><span id="line-1168"> // recreate the scanners on the current file scanners</span>
+<span class="source-line-no">1169</span><span id="line-1169"> fileScanners = store.recreateScanners(scannersToClose, cacheBlocks, false, false, matcher,</span>
+<span class="source-line-no">1170</span><span id="line-1170"> scan.getStartRow(), scan.includeStartRow(), scan.getStopRow(), scan.includeStopRow(),</span>
+<span class="source-line-no">1171</span><span id="line-1171"> readPt, false);</span>
+<span class="source-line-no">1172</span><span id="line-1172"> if (fileScanners == null) {</span>
+<span class="source-line-no">1173</span><span id="line-1173"> return;</span>
+<span class="source-line-no">1174</span><span id="line-1174"> }</span>
+<span class="source-line-no">1175</span><span id="line-1175"> seekScanners(fileScanners, lastTop, false, parallelSeekEnabled);</span>
+<span class="source-line-no">1176</span><span id="line-1176"> newCurrentScanners = new ArrayList<>(fileScanners.size() + memstoreScanners.size());</span>
+<span class="source-line-no">1177</span><span id="line-1177"> newCurrentScanners.addAll(fileScanners);</span>
+<span class="source-line-no">1178</span><span id="line-1178"> newCurrentScanners.addAll(memstoreScanners);</span>
+<span class="source-line-no">1179</span><span id="line-1179"> newHeap = newKVHeap(newCurrentScanners, comparator);</span>
+<span class="source-line-no">1180</span><span id="line-1180"> } catch (Exception e) {</span>
+<span class="source-line-no">1181</span><span id="line-1181"> LOG.warn("failed to switch to stream read", e);</span>
+<span class="source-line-no">1182</span><span id="line-1182"> if (fileScanners != null) {</span>
+<span class="source-line-no">1183</span><span id="line-1183"> fileScanners.forEach(KeyValueScanner::close);</span>
+<span class="source-line-no">1184</span><span id="line-1184"> }</span>
+<span class="source-line-no">1185</span><span id="line-1185"> return;</span>
+<span class="source-line-no">1186</span><span id="line-1186"> }</span>
+<span class="source-line-no">1187</span><span id="line-1187"> currentScanners.clear();</span>
+<span class="source-line-no">1188</span><span id="line-1188"> addCurrentScanners(newCurrentScanners);</span>
+<span class="source-line-no">1189</span><span id="line-1189"> this.heap = newHeap;</span>
+<span class="source-line-no">1190</span><span id="line-1190"> resetQueryMatcher(lastTop);</span>
+<span class="source-line-no">1191</span><span id="line-1191"> scannersToClose.forEach(KeyValueScanner::close);</span>
+<span class="source-line-no">1192</span><span id="line-1192"> if (hasSwitchedToStreamRead != null) {</span>
+<span class="source-line-no">1193</span><span id="line-1193"> hasSwitchedToStreamRead.set(true);</span>
+<span class="source-line-no">1194</span><span id="line-1194"> }</span>
+<span class="source-line-no">1195</span><span id="line-1195"> }</span>
+<span class="source-line-no">1196</span><span id="line-1196"></span>
+<span class="source-line-no">1197</span><span id="line-1197"> protected final boolean checkFlushed() {</span>
+<span class="source-line-no">1198</span><span id="line-1198"> // check the var without any lock. Suppose even if we see the old</span>
+<span class="source-line-no">1199</span><span id="line-1199"> // value here still it is ok to continue because we will not be resetting</span>
+<span class="source-line-no">1200</span><span id="line-1200"> // the heap but will continue with the referenced memstore's snapshot. For compactions</span>
+<span class="source-line-no">1201</span><span id="line-1201"> // any way we don't need the updateReaders at all to happen as we still continue with</span>
+<span class="source-line-no">1202</span><span id="line-1202"> // the older files</span>
+<span class="source-line-no">1203</span><span id="line-1203"> if (flushed) {</span>
+<span class="source-line-no">1204</span><span id="line-1204"> // If there is a flush and the current scan is notified on the flush ensure that the</span>
+<span class="source-line-no">1205</span><span id="line-1205"> // scan's heap gets reset and we do a seek on the newly flushed file.</span>
+<span class="source-line-no">1206</span><span id="line-1206"> if (this.closing) {</span>
+<span class="source-line-no">1207</span><span id="line-1207"> return false;</span>
+<span class="source-line-no">1208</span><span id="line-1208"> }</span>
+<span class="source-line-no">1209</span><span id="line-1209"> // reset the flag</span>
+<span class="source-line-no">1210</span><span id="line-1210"> flushed = false;</span>
+<span class="source-line-no">1211</span><span id="line-1211"> return true;</span>
+<span class="source-line-no">1212</span><span id="line-1212"> }</span>
+<span class="source-line-no">1213</span><span id="line-1213"> return false;</span>
+<span class="source-line-no">1214</span><span id="line-1214"> }</span>
+<span class="source-line-no">1215</span><span id="line-1215"></span>
+<span class="source-line-no">1216</span><span id="line-1216"> /**</span>
+<span class="source-line-no">1217</span><span id="line-1217"> * Seek storefiles in parallel to optimize IO latency as much as possible</span>
+<span class="source-line-no">1218</span><span id="line-1218"> * @param scanners the list {@link KeyValueScanner}s to be read from</span>
+<span class="source-line-no">1219</span><span id="line-1219"> * @param kv the KeyValue on which the operation is being requested</span>
+<span class="source-line-no">1220</span><span id="line-1220"> */</span>
+<span class="source-line-no">1221</span><span id="line-1221"> private void parallelSeek(final List<? extends KeyValueScanner> scanners, final ExtendedCell kv)</span>
+<span class="source-line-no">1222</span><span id="line-1222"> throws IOException {</span>
+<span class="source-line-no">1223</span><span id="line-1223"> if (scanners.isEmpty()) return;</span>
+<span class="source-line-no">1224</span><span id="line-1224"> int storeFileScannerCount = scanners.size();</span>
+<span class="source-line-no">1225</span><span id="line-1225"> CountDownLatch latch = new CountDownLatch(storeFileScannerCount);</span>
+<span class="source-line-no">1226</span><span id="line-1226"> List<ParallelSeekHandler> handlers = new ArrayList<>(storeFileScannerCount);</span>
+<span class="source-line-no">1227</span><span id="line-1227"> for (KeyValueScanner scanner : scanners) {</span>
+<span class="source-line-no">1228</span><span id="line-1228"> if (scanner instanceof StoreFileScanner) {</span>
+<span class="source-line-no">1229</span><span id="line-1229"> ParallelSeekHandler seekHandler = new ParallelSeekHandler(scanner, kv, this.readPt, latch);</span>
+<span class="source-line-no">1230</span><span id="line-1230"> executor.submit(seekHandler);</span>
+<span class="source-line-no">1231</span><span id="line-1231"> handlers.add(seekHandler);</span>
+<span class="source-line-no">1232</span><span id="line-1232"> } else {</span>
+<span class="source-line-no">1233</span><span id="line-1233"> scanner.seek(kv);</span>
+<span class="source-line-no">1234</span><span id="line-1234"> latch.countDown();</span>
+<span class="source-line-no">1235</span><span id="line-1235"> }</span>
+<span class="source-line-no">1236</span><span id="line-1236"> }</span>
+<span class="source-line-no">1237</span><span id="line-1237"></span>
+<span class="source-line-no">1238</span><span id="line-1238"> try {</span>
+<span class="source-line-no">1239</span><span id="line-1239"> latch.await();</span>
+<span class="source-line-no">1240</span><span id="line-1240"> } catch (InterruptedException ie) {</span>
+<span class="source-line-no">1241</span><span id="line-1241"> throw (InterruptedIOException) new InterruptedIOException().initCause(ie);</span>
+<span class="source-line-no">1242</span><span id="line-1242"> }</span>
+<span class="source-line-no">1243</span><span id="line-1243"></span>
+<span class="source-line-no">1244</span><span id="line-1244"> for (ParallelSeekHandler handler : handlers) {</span>
+<span class="source-line-no">1245</span><span id="line-1245"> if (handler.getErr() != null) {</span>
+<span class="source-line-no">1246</span><span id="line-1246"> throw new IOException(handler.getErr());</span>
+<span class="source-line-no">1247</span><span id="line-1247"> }</span>
+<span class="source-line-no">1248</span><span id="line-1248"> }</span>
+<span class="source-line-no">1249</span><span id="line-1249"> }</span>
+<span class="source-line-no">1250</span><span id="line-1250"></span>
+<span class="source-line-no">1251</span><span id="line-1251"> /**</span>
+<span class="source-line-no">1252</span><span id="line-1252"> * Used in testing.</span>
+<span class="source-line-no">1253</span><span id="line-1253"> * @return all scanners in no particular order</span>
+<span class="source-line-no">1254</span><span id="line-1254"> */</span>
+<span class="source-line-no">1255</span><span id="line-1255"> List<KeyValueScanner> getAllScannersForTesting() {</span>
+<span class="source-line-no">1256</span><span id="line-1256"> List<KeyValueScanner> allScanners = new ArrayList<>();</span>
+<span class="source-line-no">1257</span><span id="line-1257"> KeyValueScanner current = heap.getCurrentForTesting();</span>
+<span class="source-line-no">1258</span><span id="line-1258"> if (current != null) allScanners.add(current);</span>
+<span class="source-line-no">1259</span><span id="line-1259"> for (KeyValueScanner scanner : heap.getHeap())</span>
+<span class="source-line-no">1260</span><span id="line-1260"> allScanners.add(scanner);</span>
+<span class="source-line-no">1261</span><span id="line-1261"> return allScanners;</span>
+<span class="source-line-no">1262</span><span id="line-1262"> }</span>
+<span class="source-line-no">1263</span><span id="line-1263"></span>
+<span class="source-line-no">1264</span><span id="line-1264"> static void enableLazySeekGlobally(boolean enable) {</span>
+<span class="source-line-no">1265</span><span id="line-1265"> lazySeekEnabledGlobally = enable;</span>
+<span class="source-line-no">1266</span><span id="line-1266"> }</span>
+<span class="source-line-no">1267</span><span id="line-1267"></span>
+<span class="source-line-no">1268</span><span id="line-1268"> /** Returns The estimated number of KVs seen by this scanner (includes some skipped KVs). */</span>
+<span class="source-line-no">1269</span><span id="line-1269"> public long getEstimatedNumberOfKvsScanned() {</span>
+<span class="source-line-no">1270</span><span id="line-1270"> return this.kvsScanned;</span>
+<span class="source-line-no">1271</span><span id="line-1271"> }</span>
+<span class="source-line-no">1272</span><span id="line-1272"></span>
+<span class="source-line-no">1273</span><span id="line-1273"> @Override</span>
+<span class="source-line-no">1274</span><span id="line-1274"> public ExtendedCell getNextIndexedKey() {</span>
+<span class="source-line-no">1275</span><span id="line-1275"> return this.heap.getNextIndexedKey();</span>
+<span class="source-line-no">1276</span><span id="line-1276"> }</span>
+<span class="source-line-no">1277</span><span id="line-1277"></span>
+<span class="source-line-no">1278</span><span id="line-1278"> @Override</span>
+<span class="source-line-no">1279</span><span id="line-1279"> public void shipped() throws IOException {</span>
+<span class="source-line-no">1280</span><span id="line-1280"> if (prevCell != null) {</span>
+<span class="source-line-no">1281</span><span id="line-1281"> // Do the copy here so that in case the prevCell ref is pointing to the previous</span>
+<span class="source-line-no">1282</span><span id="line-1282"> // blocks we can safely release those blocks.</span>
+<span class="source-line-no">1283</span><span id="line-1283"> // This applies to blocks that are got from Bucket cache, L1 cache and the blocks</span>
+<span class="source-line-no">1284</span><span id="line-1284"> // fetched from HDFS. Copying this would ensure that we let go the references to these</span>
+<span class="source-line-no">1285</span><span id="line-1285"> // blocks so that they can be GCed safely(in case of bucket cache)</span>
+<span class="source-line-no">1286</span><span id="line-1286"> prevCell = KeyValueUtil.toNewKeyCell(this.prevCell);</span>
+<span class="source-line-no">1287</span><span id="line-1287"> }</span>
+<span class="source-line-no">1288</span><span id="line-1288"> matcher.beforeShipped();</span>
+<span class="source-line-no">1289</span><span id="line-1289"> // There wont be further fetch of Cells from these scanners. Just close.</span>
+<span class="source-line-no">1290</span><span id="line-1290"> clearAndClose(scannersForDelayedClose);</span>
+<span class="source-line-no">1291</span><span id="line-1291"> if (this.heap != null) {</span>
+<span class="source-line-no">1292</span><span id="line-1292"> this.heap.shipped();</span>
+<span class="source-line-no">1293</span><span id="line-1293"> // When switching from pread to stream, we will open a new scanner for each store file, but</span>
+<span class="source-line-no">1294</span><span id="line-1294"> // the old scanner may still track the HFileBlocks we have scanned but not sent back to client</span>
+<span class="source-line-no">1295</span><span id="line-1295"> // yet. If we close the scanner immediately then the HFileBlocks may be messed up by others</span>
+<span class="source-line-no">1296</span><span id="line-1296"> // before we serialize and send it back to client. The HFileBlocks will be released in shipped</span>
+<span class="source-line-no">1297</span><span id="line-1297"> // method, so we here will also open new scanners and close old scanners in shipped method.</span>
+<span class="source-line-no">1298</span><span id="line-1298"> // See HBASE-18055 for more details.</span>
+<span class="source-line-no">1299</span><span id="line-1299"> trySwitchToStreamRead();</span>
+<span class="source-line-no">1300</span><span id="line-1300"> }</span>
+<span class="source-line-no">1301</span><span id="line-1301"> }</span>
+<span class="source-line-no">1302</span><span id="line-1302"></span>
+<span class="source-line-no">1303</span><span id="line-1303"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1304</span><span id="line-1304"> static final void instrument() {</span>
+<span class="source-line-no">1305</span><span id="line-1305"> hasUpdatedReaders = new AtomicBoolean(false);</span>
+<span class="source-line-no">1306</span><span id="line-1306"> hasSwitchedToStreamRead = new AtomicBoolean(false);</span>
+<span class="source-line-no">1307</span><span id="line-1307"> }</span>
+<span class="source-line-no">1308</span><span id="line-1308"></span>
+<span class="source-line-no">1309</span><span id="line-1309"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1310</span><span id="line-1310"> static final boolean hasUpdatedReaders() {</span>
+<span class="source-line-no">1311</span><span id="line-1311"> return hasUpdatedReaders.get();</span>
+<span class="source-line-no">1312</span><span id="line-1312"> }</span>
+<span class="source-line-no">1313</span><span id="line-1313"></span>
+<span class="source-line-no">1314</span><span id="line-1314"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1315</span><span id="line-1315"> static final boolean hasSwitchedToStreamRead() {</span>
+<span class="source-line-no">1316</span><span id="line-1316"> return hasSwitchedToStreamRead.get();</span>
+<span class="source-line-no">1317</span><span id="line-1317"> }</span>
+<span class="source-line-no">1318</span><span id="line-1318"></span>
+<span class="source-line-no">1319</span><span id="line-1319"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1320</span><span id="line-1320"> static final void resetHasUpdatedReaders() {</span>
+<span class="source-line-no">1321</span><span id="line-1321"> hasUpdatedReaders.set(false);</span>
+<span class="source-line-no">1322</span><span id="line-1322"> }</span>
+<span class="source-line-no">1323</span><span id="line-1323"></span>
+<span class="source-line-no">1324</span><span id="line-1324"> @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.UNITTEST)</span>
+<span class="source-line-no">1325</span><span id="line-1325"> static final void resetHasSwitchedToStreamRead() {</span>
+<span class="source-line-no">1326</span><span id="line-1326"> hasSwitchedToStreamRead.set(false);</span>
+<span class="source-line-no">1327</span><span id="line-1327"> }</span>
+<span class="source-line-no">1328</span><span id="line-1328">}</span>
diff --git a/hbase-website/dependency-convergence.html b/hbase-website/dependency-convergence.html
index a9a09e44eac..72cc661b4e2 100644
--- a/hbase-website/dependency-convergence.html
+++ b/hbase-website/dependency-convergence.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-convergence at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-convergence at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/dependency-info.html b/hbase-website/dependency-info.html
index e0fe7bde829..5f5d35eb462 100644
--- a/hbase-website/dependency-info.html
+++ b/hbase-website/dependency-info.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-info at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-info at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/dependency-management.html b/hbase-website/dependency-management.html
index 7254fb9cb71..33bf98c39b7 100644
--- a/hbase-website/dependency-management.html
+++ b/hbase-website/dependency-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:dependency-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/index.html b/hbase-website/index.html
index e981cab9fdf..9b61e7987dc 100644
--- a/hbase-website/index.html
+++ b/hbase-website/index.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:index at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:index at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/issue-management.html b/hbase-website/issue-management.html
index 0f7f673ee17..78fc25b9871 100644
--- a/hbase-website/issue-management.html
+++ b/hbase-website/issue-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:issue-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:issue-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/licenses.html b/hbase-website/licenses.html
index 00cb343263c..14fd2a8e5cf 100644
--- a/hbase-website/licenses.html
+++ b/hbase-website/licenses.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:licenses at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:licenses at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/mailing-lists.html b/hbase-website/mailing-lists.html
index d2e662d4e61..e8effda8a90 100644
--- a/hbase-website/mailing-lists.html
+++ b/hbase-website/mailing-lists.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:mailing-lists at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:mailing-lists at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/plugin-management.html b/hbase-website/plugin-management.html
index 3f5d397eeb8..eb35cc06294 100644
--- a/hbase-website/plugin-management.html
+++ b/hbase-website/plugin-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugin-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugin-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/plugins.html b/hbase-website/plugins.html
index 64e997ec22c..a7824e8739d 100644
--- a/hbase-website/plugins.html
+++ b/hbase-website/plugins.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugins at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugins at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/project-info.html b/hbase-website/project-info.html
index 6a95645564f..6476847890e 100644
--- a/hbase-website/project-info.html
+++ b/hbase-website/project-info.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/scm.html b/hbase-website/scm.html
index 5860b672181..5a9a9b30101 100644
--- a/hbase-website/scm.html
+++ b/hbase-website/scm.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:scm at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:scm at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/summary.html b/hbase-website/summary.html
index 703431273cf..9420585fb95 100644
--- a/hbase-website/summary.html
+++ b/hbase-website/summary.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:summary at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:summary at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/hbase-website/team.html b/hbase-website/team.html
index b8f348c0b00..93911e26810 100644
--- a/hbase-website/team.html
+++ b/hbase-website/team.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:team at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:team at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/issue-management.html b/issue-management.html
index 8fd10032b8a..a841595c371 100644
--- a/issue-management.html
+++ b/issue-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:issue-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:issue-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/licenses.html b/licenses.html
index 46404570d38..53cc23291b4 100644
--- a/licenses.html
+++ b/licenses.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:licenses at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:licenses at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/mailing-lists.html b/mailing-lists.html
index 4e2c6f1b1f6..7cbd4b1d0e2 100644
--- a/mailing-lists.html
+++ b/mailing-lists.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:mailing-lists at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:mailing-lists at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/plugin-management.html b/plugin-management.html
index 974e3a73b0d..1f7f356a36d 100644
--- a/plugin-management.html
+++ b/plugin-management.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugin-management at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugin-management at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/plugins.html b/plugins.html
index a4569091f48..d0d1c49897e 100644
--- a/plugins.html
+++ b/plugins.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugins at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:plugins at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/project-info.html b/project-info.html
index ddaf0c8ea76..c859036baa5 100644
--- a/project-info.html
+++ b/project-info.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/project-reports.html b/project-reports.html
index 294c75d5c86..76c83493692 100644
--- a/project-reports.html
+++ b/project-reports.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-reports at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-reports at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/scm.html b/scm.html
index 1aaf45c9e08..a111582fdc9 100644
--- a/scm.html
+++ b/scm.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:scm at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:scm at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/summary.html b/summary.html
index f43e7d59695..c0e438679b7 100644
--- a/summary.html
+++ b/summary.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:summary at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:summary at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/team.html b/team.html
index a74ef60e658..55d91606591 100644
--- a/team.html
+++ b/team.html
@@ -2,7 +2,7 @@
<!--
- | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:team at 02/25/26
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-project-info-reports-plugin:3.9.0:team at 02/26/26
| Rendered using Apache Maven Fluido Skin 2.0.0-M9
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">