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/09/10 00:00:23 UTC

(hbase-site) branch asf-site updated: Published site at 50757d0ce9054766a628ca67dae0b656957cf043.

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

asf-gitbox-commits 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 70254b0ed81 Published site at 50757d0ce9054766a628ca67dae0b656957cf043.
70254b0ed81 is described below

commit 70254b0ed819e0a2f52e66c85265dd5789fe8526
Author: HBase <de...@hbase.apache.org>
AuthorDate: Wed Sep 9 23:54:25 2026 +0000

    Published site at 50757d0ce9054766a628ca67dae0b656957cf043.
---
 .../hadoop/hbase/client/TableSnapshotScanner.html  |  434 ++++----
 .../TableSnapshotInputFormatImpl.InputSplit.html   |    2 +-
 .../TableSnapshotInputFormatImpl.RecordReader.html |    2 +-
 .../mapreduce/TableSnapshotInputFormatImpl.html    |    2 +-
 books/apache-hbase-reference-guide-dark-mode.pdf   |  Bin 38775819 -> 38775817 bytes
 books/apache-hbase-reference-guide.pdf             |  Bin 38665189 -> 38665189 bytes
 checkstyle-aggregate.html                          |    2 +-
 dependency-convergence.html                        |    2 +-
 dependency-info.html                               |    2 +-
 dependency-management.html                         |    2 +-
 .../hadoop/hbase/client/TableSnapshotScanner.html  |   48 +-
 .../hadoop/hbase/client/TableSnapshotScanner.html  |  434 ++++----
 .../TableSnapshotInputFormatImpl.InputSplit.html   |    2 +-
 .../TableSnapshotInputFormatImpl.RecordReader.html |    2 +-
 .../mapreduce/TableSnapshotInputFormatImpl.html    |    2 +-
 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 +-
 testapidocs/index-all.html                         |    2 +
 testapidocs/member-search-index.js                 |    2 +-
 .../hbase/client/TestTableSnapshotScanner.html     | 1156 ++++++++++----------
 testdevapidocs/index-all.html                      |    2 +
 testdevapidocs/member-search-index.js              |    2 +-
 .../hbase/client/TestTableSnapshotScanner.html     |  109 +-
 .../client/TestTableSnapshotScannerWithSFT.html    |    2 +-
 .../hbase/master/assignment/TestRollbackSCP.html   |    6 +-
 .../hbase/client/TestTableSnapshotScanner.html     | 1156 ++++++++++----------
 .../TestRollbackSCP.AssignmentManagerForTest.html  |   99 +-
 .../assignment/TestRollbackSCP.HMasterForTest.html |   99 +-
 .../hbase/master/assignment/TestRollbackSCP.html   |   99 +-
 50 files changed, 1907 insertions(+), 1809 deletions(-)

diff --git a/apidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html b/apidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
index 9217df49239..5c7d1bfa0e1 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
@@ -39,220 +39,226 @@
 <span class="source-line-no">026</span><span id="line-26">import org.apache.hadoop.fs.Path;</span>
 <span class="source-line-no">027</span><span id="line-27">import org.apache.hadoop.hbase.PrivateCellUtil;</span>
 <span class="source-line-no">028</span><span id="line-28">import org.apache.hadoop.hbase.client.metrics.ScanMetrics;</span>
-<span class="source-line-no">029</span><span id="line-29">import org.apache.hadoop.hbase.regionserver.MemStoreLAB;</span>
-<span class="source-line-no">030</span><span id="line-30">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
-<span class="source-line-no">031</span><span id="line-31">import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;</span>
-<span class="source-line-no">032</span><span id="line-32">import org.apache.hadoop.hbase.snapshot.SnapshotManifest;</span>
-<span class="source-line-no">033</span><span id="line-33">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
-<span class="source-line-no">034</span><span id="line-34">import org.apache.yetus.audience.InterfaceAudience;</span>
-<span class="source-line-no">035</span><span id="line-35">import org.slf4j.Logger;</span>
-<span class="source-line-no">036</span><span id="line-36">import org.slf4j.LoggerFactory;</span>
-<span class="source-line-no">037</span><span id="line-37"></span>
-<span class="source-line-no">038</span><span id="line-38">import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;</span>
-<span class="source-line-no">039</span><span id="line-39">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;</span>
-<span class="source-line-no">040</span><span id="line-40">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;</span>
-<span class="source-line-no">041</span><span id="line-41"></span>
-<span class="source-line-no">042</span><span id="line-42">/**</span>
-<span class="source-line-no">043</span><span id="line-43"> * A Scanner which performs a scan over snapshot files. Using this class requires copying the</span>
-<span class="source-line-no">044</span><span id="line-44"> * snapshot to a temporary empty directory, which will copy the snapshot reference files into that</span>
-<span class="source-line-no">045</span><span id="line-45"> * directory. Actual data files are not copied.</span>
-<span class="source-line-no">046</span><span id="line-46"> * &lt;p&gt;</span>
-<span class="source-line-no">047</span><span id="line-47"> * This also allows one to run the scan from an online or offline hbase cluster. The snapshot files</span>
-<span class="source-line-no">048</span><span id="line-48"> * can be exported by using the org.apache.hadoop.hbase.snapshot.ExportSnapshot tool, to a pure-hdfs</span>
-<span class="source-line-no">049</span><span id="line-49"> * cluster, and this scanner can be used to run the scan directly over the snapshot files. The</span>
-<span class="source-line-no">050</span><span id="line-50"> * snapshot should not be deleted while there are open scanners reading from snapshot files.</span>
-<span class="source-line-no">051</span><span id="line-51"> * &lt;p&gt;</span>
-<span class="source-line-no">052</span><span id="line-52"> * An internal RegionScanner is used to execute the {@link Scan} obtained from the user for each</span>
-<span class="source-line-no">053</span><span id="line-53"> * region in the snapshot.</span>
-<span class="source-line-no">054</span><span id="line-54"> * &lt;p&gt;</span>
-<span class="source-line-no">055</span><span id="line-55"> * HBase owns all the data and snapshot files on the filesystem. Only the HBase user can read from</span>
-<span class="source-line-no">056</span><span id="line-56"> * snapshot files and data files. HBase also enforces security because all the requests are handled</span>
-<span class="source-line-no">057</span><span id="line-57"> * by the server layer, and the user cannot read from the data files directly. To read from snapshot</span>
-<span class="source-line-no">058</span><span id="line-58"> * files directly from the file system, the user who is running the MR job must have sufficient</span>
-<span class="source-line-no">059</span><span id="line-59"> * permissions to access snapshot and reference files. This means that to run mapreduce over</span>
-<span class="source-line-no">060</span><span id="line-60"> * snapshot files, the job has to be run as the HBase user or the user must have group or other</span>
-<span class="source-line-no">061</span><span id="line-61"> * priviledges in the filesystem (See HBASE-8369). Note that, given other users access to read from</span>
-<span class="source-line-no">062</span><span id="line-62"> * snapshot/data files will completely circumvent the access control enforced by HBase. See</span>
-<span class="source-line-no">063</span><span id="line-63"> * org.apache.hadoop.hbase.mapreduce.TableSnapshotInputFormat.</span>
-<span class="source-line-no">064</span><span id="line-64"> */</span>
-<span class="source-line-no">065</span><span id="line-65">@InterfaceAudience.Private</span>
-<span class="source-line-no">066</span><span id="line-66">public class TableSnapshotScanner extends AbstractClientScanner {</span>
-<span class="source-line-no">067</span><span id="line-67"></span>
-<span class="source-line-no">068</span><span id="line-68">  private static final Logger LOG = LoggerFactory.getLogger(TableSnapshotScanner.class);</span>
-<span class="source-line-no">069</span><span id="line-69"></span>
-<span class="source-line-no">070</span><span id="line-70">  private Configuration conf;</span>
-<span class="source-line-no">071</span><span id="line-71">  private String snapshotName;</span>
-<span class="source-line-no">072</span><span id="line-72">  private FileSystem fs;</span>
-<span class="source-line-no">073</span><span id="line-73">  private Path rootDir;</span>
-<span class="source-line-no">074</span><span id="line-74">  private Path restoreDir;</span>
-<span class="source-line-no">075</span><span id="line-75">  private Scan scan;</span>
-<span class="source-line-no">076</span><span id="line-76">  private ArrayList&lt;RegionInfo&gt; regions;</span>
-<span class="source-line-no">077</span><span id="line-77">  private TableDescriptor htd;</span>
-<span class="source-line-no">078</span><span id="line-78">  private final boolean snapshotAlreadyRestored;</span>
-<span class="source-line-no">079</span><span id="line-79"></span>
-<span class="source-line-no">080</span><span id="line-80">  private ClientSideRegionScanner currentRegionScanner = null;</span>
-<span class="source-line-no">081</span><span id="line-81">  private int currentRegion = -1;</span>
-<span class="source-line-no">082</span><span id="line-82"></span>
-<span class="source-line-no">083</span><span id="line-83">  private int numOfCompleteRows = 0;</span>
-<span class="source-line-no">084</span><span id="line-84"></span>
-<span class="source-line-no">085</span><span id="line-85">  /**</span>
-<span class="source-line-no">086</span><span id="line-86">   * Creates a TableSnapshotScanner.</span>
-<span class="source-line-no">087</span><span id="line-87">   * @param conf         the configuration</span>
-<span class="source-line-no">088</span><span id="line-88">   * @param restoreDir   a temporary directory to copy the snapshot files into. Current user should</span>
-<span class="source-line-no">089</span><span id="line-89">   *                     have write permissions to this directory, and this should not be a</span>
-<span class="source-line-no">090</span><span id="line-90">   *                     subdirectory of rootDir. The scanner deletes the contents of the directory</span>
-<span class="source-line-no">091</span><span id="line-91">   *                     once the scanner is closed.</span>
-<span class="source-line-no">092</span><span id="line-92">   * @param snapshotName the name of the snapshot to read from</span>
-<span class="source-line-no">093</span><span id="line-93">   * @param scan         a Scan representing scan parameters</span>
-<span class="source-line-no">094</span><span id="line-94">   * @throws IOException in case of error</span>
-<span class="source-line-no">095</span><span id="line-95">   */</span>
-<span class="source-line-no">096</span><span id="line-96">  public TableSnapshotScanner(Configuration conf, Path restoreDir, String snapshotName, Scan scan)</span>
-<span class="source-line-no">097</span><span id="line-97">    throws IOException {</span>
-<span class="source-line-no">098</span><span id="line-98">    this(conf, CommonFSUtils.getRootDir(conf), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">099</span><span id="line-99">  }</span>
-<span class="source-line-no">100</span><span id="line-100"></span>
-<span class="source-line-no">101</span><span id="line-101">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
-<span class="source-line-no">102</span><span id="line-102">    String snapshotName, Scan scan) throws IOException {</span>
-<span class="source-line-no">103</span><span id="line-103">    this(conf, rootDir, restoreDir, snapshotName, scan, false);</span>
-<span class="source-line-no">104</span><span id="line-104">  }</span>
-<span class="source-line-no">105</span><span id="line-105"></span>
-<span class="source-line-no">106</span><span id="line-106">  /**</span>
-<span class="source-line-no">107</span><span id="line-107">   * Creates a TableSnapshotScanner.</span>
-<span class="source-line-no">108</span><span id="line-108">   * @param conf                    the configuration</span>
-<span class="source-line-no">109</span><span id="line-109">   * @param rootDir                 root directory for HBase.</span>
-<span class="source-line-no">110</span><span id="line-110">   * @param restoreDir              a temporary directory to copy the snapshot files into. Current</span>
-<span class="source-line-no">111</span><span id="line-111">   *                                user should have write permissions to this directory, and this</span>
-<span class="source-line-no">112</span><span id="line-112">   *                                should not be a subdirectory of rootdir. The scanner deletes the</span>
-<span class="source-line-no">113</span><span id="line-113">   *                                contents of the directory once the scanner is closed.</span>
-<span class="source-line-no">114</span><span id="line-114">   * @param snapshotName            the name of the snapshot to read from</span>
-<span class="source-line-no">115</span><span id="line-115">   * @param scan                    a Scan representing scan parameters</span>
-<span class="source-line-no">116</span><span id="line-116">   * @param snapshotAlreadyRestored true to indicate that snapshot has been restored.</span>
-<span class="source-line-no">117</span><span id="line-117">   * @throws IOException in case of error</span>
-<span class="source-line-no">118</span><span id="line-118">   */</span>
-<span class="source-line-no">119</span><span id="line-119">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
-<span class="source-line-no">120</span><span id="line-120">    String snapshotName, Scan scan, boolean snapshotAlreadyRestored) throws IOException {</span>
-<span class="source-line-no">121</span><span id="line-121">    this.conf = conf;</span>
-<span class="source-line-no">122</span><span id="line-122">    this.snapshotName = snapshotName;</span>
-<span class="source-line-no">123</span><span id="line-123">    this.rootDir = rootDir;</span>
-<span class="source-line-no">124</span><span id="line-124">    this.scan = scan;</span>
-<span class="source-line-no">125</span><span id="line-125">    this.snapshotAlreadyRestored = snapshotAlreadyRestored;</span>
-<span class="source-line-no">126</span><span id="line-126">    this.fs = rootDir.getFileSystem(conf);</span>
-<span class="source-line-no">127</span><span id="line-127">    conf.setBoolean(MemStoreLAB.USEMSLAB_KEY, false);</span>
-<span class="source-line-no">128</span><span id="line-128"></span>
-<span class="source-line-no">129</span><span id="line-129">    if (snapshotAlreadyRestored) {</span>
-<span class="source-line-no">130</span><span id="line-130">      this.restoreDir = restoreDir;</span>
-<span class="source-line-no">131</span><span id="line-131">      openWithoutRestoringSnapshot();</span>
-<span class="source-line-no">132</span><span id="line-132">    } else {</span>
-<span class="source-line-no">133</span><span id="line-133">      // restoreDir will be deleted in close(), use a unique sub directory</span>
-<span class="source-line-no">134</span><span id="line-134">      this.restoreDir = new Path(restoreDir, UUID.randomUUID().toString());</span>
-<span class="source-line-no">135</span><span id="line-135">      openWithRestoringSnapshot();</span>
-<span class="source-line-no">136</span><span id="line-136">    }</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">    initScanMetrics(scan);</span>
-<span class="source-line-no">139</span><span id="line-139">  }</span>
-<span class="source-line-no">140</span><span id="line-140"></span>
-<span class="source-line-no">141</span><span id="line-141">  private void openWithoutRestoringSnapshot() throws IOException {</span>
-<span class="source-line-no">142</span><span id="line-142">    Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);</span>
-<span class="source-line-no">143</span><span id="line-143">    SnapshotProtos.SnapshotDescription snapshotDesc =</span>
-<span class="source-line-no">144</span><span id="line-144">      SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);</span>
-<span class="source-line-no">145</span><span id="line-145"></span>
-<span class="source-line-no">146</span><span id="line-146">    SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshotDesc);</span>
-<span class="source-line-no">147</span><span id="line-147">    List&lt;SnapshotRegionManifest&gt; regionManifests = manifest.getRegionManifests();</span>
-<span class="source-line-no">148</span><span id="line-148">    if (regionManifests == null) {</span>
-<span class="source-line-no">149</span><span id="line-149">      throw new IllegalArgumentException("Snapshot seems empty, snapshotName: " + snapshotName);</span>
-<span class="source-line-no">150</span><span id="line-150">    }</span>
-<span class="source-line-no">151</span><span id="line-151"></span>
-<span class="source-line-no">152</span><span id="line-152">    regions = new ArrayList&lt;&gt;(regionManifests.size());</span>
-<span class="source-line-no">153</span><span id="line-153">    regionManifests.stream().map(r -&gt; ProtobufUtil.toRegionInfo(r.getRegionInfo()))</span>
-<span class="source-line-no">154</span><span id="line-154">      .filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
-<span class="source-line-no">155</span><span id="line-155">    htd = manifest.getTableDescriptor();</span>
-<span class="source-line-no">156</span><span id="line-156">  }</span>
-<span class="source-line-no">157</span><span id="line-157"></span>
-<span class="source-line-no">158</span><span id="line-158">  private boolean isValidRegion(RegionInfo hri) {</span>
-<span class="source-line-no">159</span><span id="line-159">    // An offline split parent region should be excluded.</span>
-<span class="source-line-no">160</span><span id="line-160">    if (hri.isOffline() &amp;&amp; (hri.isSplit() || hri.isSplitParent())) {</span>
-<span class="source-line-no">161</span><span id="line-161">      return false;</span>
-<span class="source-line-no">162</span><span id="line-162">    }</span>
-<span class="source-line-no">163</span><span id="line-163">    return PrivateCellUtil.overlappingKeys(scan.getStartRow(), scan.getStopRow(), hri.getStartKey(),</span>
-<span class="source-line-no">164</span><span id="line-164">      hri.getEndKey());</span>
-<span class="source-line-no">165</span><span id="line-165">  }</span>
-<span class="source-line-no">166</span><span id="line-166"></span>
-<span class="source-line-no">167</span><span id="line-167">  private void openWithRestoringSnapshot() throws IOException {</span>
-<span class="source-line-no">168</span><span id="line-168">    final RestoreSnapshotHelper.RestoreMetaChanges meta =</span>
-<span class="source-line-no">169</span><span id="line-169">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">170</span><span id="line-170">    final List&lt;RegionInfo&gt; restoredRegions = meta.getRegionsToAdd();</span>
-<span class="source-line-no">171</span><span id="line-171"></span>
-<span class="source-line-no">172</span><span id="line-172">    htd = meta.getTableDescriptor();</span>
-<span class="source-line-no">173</span><span id="line-173">    regions = new ArrayList&lt;&gt;(restoredRegions.size());</span>
-<span class="source-line-no">174</span><span id="line-174">    restoredRegions.stream().filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
-<span class="source-line-no">175</span><span id="line-175">  }</span>
-<span class="source-line-no">176</span><span id="line-176"></span>
-<span class="source-line-no">177</span><span id="line-177">  @Override</span>
-<span class="source-line-no">178</span><span id="line-178">  public Result next() throws IOException {</span>
-<span class="source-line-no">179</span><span id="line-179">    Result result = null;</span>
-<span class="source-line-no">180</span><span id="line-180">    while (true) {</span>
-<span class="source-line-no">181</span><span id="line-181">      if (currentRegionScanner == null) {</span>
-<span class="source-line-no">182</span><span id="line-182">        currentRegion++;</span>
-<span class="source-line-no">183</span><span id="line-183">        if (currentRegion &gt;= regions.size()) {</span>
-<span class="source-line-no">184</span><span id="line-184">          return null;</span>
-<span class="source-line-no">185</span><span id="line-185">        }</span>
-<span class="source-line-no">186</span><span id="line-186"></span>
-<span class="source-line-no">187</span><span id="line-187">        RegionInfo hri = regions.get(currentRegion);</span>
-<span class="source-line-no">188</span><span id="line-188">        currentRegionScanner =</span>
-<span class="source-line-no">189</span><span id="line-189">          new ClientSideRegionScanner(conf, fs, restoreDir, htd, hri, scan, scanMetrics);</span>
-<span class="source-line-no">190</span><span id="line-190">        if (this.scanMetrics != null) {</span>
-<span class="source-line-no">191</span><span id="line-191">          this.scanMetrics.addToCounter(ScanMetrics.REGIONS_SCANNED_METRIC_NAME, 1);</span>
-<span class="source-line-no">192</span><span id="line-192">        }</span>
-<span class="source-line-no">193</span><span id="line-193">      }</span>
-<span class="source-line-no">194</span><span id="line-194"></span>
-<span class="source-line-no">195</span><span id="line-195">      try {</span>
-<span class="source-line-no">196</span><span id="line-196">        result = currentRegionScanner.next();</span>
-<span class="source-line-no">197</span><span id="line-197">        if (result != null) {</span>
-<span class="source-line-no">198</span><span id="line-198">          if (scan.getLimit() &gt; 0 &amp;&amp; ++this.numOfCompleteRows &gt; scan.getLimit()) {</span>
-<span class="source-line-no">199</span><span id="line-199">            result = null;</span>
-<span class="source-line-no">200</span><span id="line-200">          }</span>
-<span class="source-line-no">201</span><span id="line-201">          return result;</span>
-<span class="source-line-no">202</span><span id="line-202">        }</span>
-<span class="source-line-no">203</span><span id="line-203">      } finally {</span>
-<span class="source-line-no">204</span><span id="line-204">        if (result == null) {</span>
-<span class="source-line-no">205</span><span id="line-205">          currentRegionScanner.close();</span>
-<span class="source-line-no">206</span><span id="line-206">          currentRegionScanner = null;</span>
-<span class="source-line-no">207</span><span id="line-207">        }</span>
-<span class="source-line-no">208</span><span id="line-208">      }</span>
-<span class="source-line-no">209</span><span id="line-209">    }</span>
-<span class="source-line-no">210</span><span id="line-210">  }</span>
-<span class="source-line-no">211</span><span id="line-211"></span>
-<span class="source-line-no">212</span><span id="line-212">  private void cleanup() {</span>
-<span class="source-line-no">213</span><span id="line-213">    try {</span>
-<span class="source-line-no">214</span><span id="line-214">      if (fs.exists(this.restoreDir)) {</span>
-<span class="source-line-no">215</span><span id="line-215">        if (!fs.delete(this.restoreDir, true)) {</span>
-<span class="source-line-no">216</span><span id="line-216">          LOG.warn(</span>
-<span class="source-line-no">217</span><span id="line-217">            "Delete restore directory for the snapshot failed. restoreDir: " + this.restoreDir);</span>
-<span class="source-line-no">218</span><span id="line-218">        }</span>
-<span class="source-line-no">219</span><span id="line-219">      }</span>
-<span class="source-line-no">220</span><span id="line-220">    } catch (IOException ex) {</span>
-<span class="source-line-no">221</span><span id="line-221">      LOG.warn(</span>
-<span class="source-line-no">222</span><span id="line-222">        "Could not delete restore directory for the snapshot. restoreDir: " + this.restoreDir, ex);</span>
-<span class="source-line-no">223</span><span id="line-223">    }</span>
-<span class="source-line-no">224</span><span id="line-224">  }</span>
-<span class="source-line-no">225</span><span id="line-225"></span>
-<span class="source-line-no">226</span><span id="line-226">  @Override</span>
-<span class="source-line-no">227</span><span id="line-227">  public void close() {</span>
-<span class="source-line-no">228</span><span id="line-228">    if (currentRegionScanner != null) {</span>
-<span class="source-line-no">229</span><span id="line-229">      currentRegionScanner.close();</span>
-<span class="source-line-no">230</span><span id="line-230">    }</span>
-<span class="source-line-no">231</span><span id="line-231">    // if snapshotAlreadyRestored is true, then we should invoke cleanup() method by hand.</span>
-<span class="source-line-no">232</span><span id="line-232">    if (!this.snapshotAlreadyRestored) {</span>
-<span class="source-line-no">233</span><span id="line-233">      cleanup();</span>
-<span class="source-line-no">234</span><span id="line-234">    }</span>
-<span class="source-line-no">235</span><span id="line-235">  }</span>
-<span class="source-line-no">236</span><span id="line-236"></span>
-<span class="source-line-no">237</span><span id="line-237">  @Override</span>
-<span class="source-line-no">238</span><span id="line-238">  public boolean renewLease() {</span>
-<span class="source-line-no">239</span><span id="line-239">    throw new UnsupportedOperationException();</span>
-<span class="source-line-no">240</span><span id="line-240">  }</span>
-<span class="source-line-no">241</span><span id="line-241"></span>
-<span class="source-line-no">242</span><span id="line-242">}</span>
+<span class="source-line-no">029</span><span id="line-29">import org.apache.hadoop.hbase.mob.MobUtils;</span>
+<span class="source-line-no">030</span><span id="line-30">import org.apache.hadoop.hbase.regionserver.MemStoreLAB;</span>
+<span class="source-line-no">031</span><span id="line-31">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
+<span class="source-line-no">032</span><span id="line-32">import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;</span>
+<span class="source-line-no">033</span><span id="line-33">import org.apache.hadoop.hbase.snapshot.SnapshotManifest;</span>
+<span class="source-line-no">034</span><span id="line-34">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
+<span class="source-line-no">035</span><span id="line-35">import org.apache.yetus.audience.InterfaceAudience;</span>
+<span class="source-line-no">036</span><span id="line-36">import org.slf4j.Logger;</span>
+<span class="source-line-no">037</span><span id="line-37">import org.slf4j.LoggerFactory;</span>
+<span class="source-line-no">038</span><span id="line-38"></span>
+<span class="source-line-no">039</span><span id="line-39">import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;</span>
+<span class="source-line-no">040</span><span id="line-40">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;</span>
+<span class="source-line-no">041</span><span id="line-41">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;</span>
+<span class="source-line-no">042</span><span id="line-42"></span>
+<span class="source-line-no">043</span><span id="line-43">/**</span>
+<span class="source-line-no">044</span><span id="line-44"> * A Scanner which performs a scan over snapshot files. Using this class requires copying the</span>
+<span class="source-line-no">045</span><span id="line-45"> * snapshot to a temporary empty directory, which will copy the snapshot reference files into that</span>
+<span class="source-line-no">046</span><span id="line-46"> * directory. Actual data files are not copied.</span>
+<span class="source-line-no">047</span><span id="line-47"> * &lt;p&gt;</span>
+<span class="source-line-no">048</span><span id="line-48"> * This also allows one to run the scan from an online or offline hbase cluster. The snapshot files</span>
+<span class="source-line-no">049</span><span id="line-49"> * can be exported by using the org.apache.hadoop.hbase.snapshot.ExportSnapshot tool, to a pure-hdfs</span>
+<span class="source-line-no">050</span><span id="line-50"> * cluster, and this scanner can be used to run the scan directly over the snapshot files. The</span>
+<span class="source-line-no">051</span><span id="line-51"> * snapshot should not be deleted while there are open scanners reading from snapshot files.</span>
+<span class="source-line-no">052</span><span id="line-52"> * &lt;p&gt;</span>
+<span class="source-line-no">053</span><span id="line-53"> * An internal RegionScanner is used to execute the {@link Scan} obtained from the user for each</span>
+<span class="source-line-no">054</span><span id="line-54"> * region in the snapshot.</span>
+<span class="source-line-no">055</span><span id="line-55"> * &lt;p&gt;</span>
+<span class="source-line-no">056</span><span id="line-56"> * HBase owns all the data and snapshot files on the filesystem. Only the HBase user can read from</span>
+<span class="source-line-no">057</span><span id="line-57"> * snapshot files and data files. HBase also enforces security because all the requests are handled</span>
+<span class="source-line-no">058</span><span id="line-58"> * by the server layer, and the user cannot read from the data files directly. To read from snapshot</span>
+<span class="source-line-no">059</span><span id="line-59"> * files directly from the file system, the user who is running the MR job must have sufficient</span>
+<span class="source-line-no">060</span><span id="line-60"> * permissions to access snapshot and reference files. This means that to run mapreduce over</span>
+<span class="source-line-no">061</span><span id="line-61"> * snapshot files, the job has to be run as the HBase user or the user must have group or other</span>
+<span class="source-line-no">062</span><span id="line-62"> * priviledges in the filesystem (See HBASE-8369). Note that, given other users access to read from</span>
+<span class="source-line-no">063</span><span id="line-63"> * snapshot/data files will completely circumvent the access control enforced by HBase. See</span>
+<span class="source-line-no">064</span><span id="line-64"> * org.apache.hadoop.hbase.mapreduce.TableSnapshotInputFormat.</span>
+<span class="source-line-no">065</span><span id="line-65"> */</span>
+<span class="source-line-no">066</span><span id="line-66">@InterfaceAudience.Private</span>
+<span class="source-line-no">067</span><span id="line-67">public class TableSnapshotScanner extends AbstractClientScanner {</span>
+<span class="source-line-no">068</span><span id="line-68"></span>
+<span class="source-line-no">069</span><span id="line-69">  private static final Logger LOG = LoggerFactory.getLogger(TableSnapshotScanner.class);</span>
+<span class="source-line-no">070</span><span id="line-70"></span>
+<span class="source-line-no">071</span><span id="line-71">  private Configuration conf;</span>
+<span class="source-line-no">072</span><span id="line-72">  private String snapshotName;</span>
+<span class="source-line-no">073</span><span id="line-73">  private FileSystem fs;</span>
+<span class="source-line-no">074</span><span id="line-74">  private Path rootDir;</span>
+<span class="source-line-no">075</span><span id="line-75">  private Path restoreDir;</span>
+<span class="source-line-no">076</span><span id="line-76">  private Scan scan;</span>
+<span class="source-line-no">077</span><span id="line-77">  private ArrayList&lt;RegionInfo&gt; regions;</span>
+<span class="source-line-no">078</span><span id="line-78">  private TableDescriptor htd;</span>
+<span class="source-line-no">079</span><span id="line-79">  private final boolean snapshotAlreadyRestored;</span>
+<span class="source-line-no">080</span><span id="line-80"></span>
+<span class="source-line-no">081</span><span id="line-81">  private ClientSideRegionScanner currentRegionScanner = null;</span>
+<span class="source-line-no">082</span><span id="line-82">  private int currentRegion = -1;</span>
+<span class="source-line-no">083</span><span id="line-83"></span>
+<span class="source-line-no">084</span><span id="line-84">  private int numOfCompleteRows = 0;</span>
+<span class="source-line-no">085</span><span id="line-85"></span>
+<span class="source-line-no">086</span><span id="line-86">  /**</span>
+<span class="source-line-no">087</span><span id="line-87">   * Creates a TableSnapshotScanner.</span>
+<span class="source-line-no">088</span><span id="line-88">   * @param conf         the configuration</span>
+<span class="source-line-no">089</span><span id="line-89">   * @param restoreDir   a temporary directory to copy the snapshot files into. Current user should</span>
+<span class="source-line-no">090</span><span id="line-90">   *                     have write permissions to this directory, and this should not be a</span>
+<span class="source-line-no">091</span><span id="line-91">   *                     subdirectory of rootDir. The scanner deletes the contents of the directory</span>
+<span class="source-line-no">092</span><span id="line-92">   *                     once the scanner is closed.</span>
+<span class="source-line-no">093</span><span id="line-93">   * @param snapshotName the name of the snapshot to read from</span>
+<span class="source-line-no">094</span><span id="line-94">   * @param scan         a Scan representing scan parameters</span>
+<span class="source-line-no">095</span><span id="line-95">   * @throws IOException in case of error</span>
+<span class="source-line-no">096</span><span id="line-96">   */</span>
+<span class="source-line-no">097</span><span id="line-97">  public TableSnapshotScanner(Configuration conf, Path restoreDir, String snapshotName, Scan scan)</span>
+<span class="source-line-no">098</span><span id="line-98">    throws IOException {</span>
+<span class="source-line-no">099</span><span id="line-99">    this(conf, CommonFSUtils.getRootDir(conf), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">100</span><span id="line-100">  }</span>
+<span class="source-line-no">101</span><span id="line-101"></span>
+<span class="source-line-no">102</span><span id="line-102">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
+<span class="source-line-no">103</span><span id="line-103">    String snapshotName, Scan scan) throws IOException {</span>
+<span class="source-line-no">104</span><span id="line-104">    this(conf, rootDir, restoreDir, snapshotName, scan, false);</span>
+<span class="source-line-no">105</span><span id="line-105">  }</span>
+<span class="source-line-no">106</span><span id="line-106"></span>
+<span class="source-line-no">107</span><span id="line-107">  /**</span>
+<span class="source-line-no">108</span><span id="line-108">   * Creates a TableSnapshotScanner.</span>
+<span class="source-line-no">109</span><span id="line-109">   * @param conf                    the configuration</span>
+<span class="source-line-no">110</span><span id="line-110">   * @param rootDir                 root directory for HBase.</span>
+<span class="source-line-no">111</span><span id="line-111">   * @param restoreDir              a temporary directory to copy the snapshot files into. Current</span>
+<span class="source-line-no">112</span><span id="line-112">   *                                user should have write permissions to this directory, and this</span>
+<span class="source-line-no">113</span><span id="line-113">   *                                should not be a subdirectory of rootdir. The scanner deletes the</span>
+<span class="source-line-no">114</span><span id="line-114">   *                                contents of the directory once the scanner is closed.</span>
+<span class="source-line-no">115</span><span id="line-115">   * @param snapshotName            the name of the snapshot to read from</span>
+<span class="source-line-no">116</span><span id="line-116">   * @param scan                    a Scan representing scan parameters</span>
+<span class="source-line-no">117</span><span id="line-117">   * @param snapshotAlreadyRestored true to indicate that snapshot has been restored.</span>
+<span class="source-line-no">118</span><span id="line-118">   * @throws IOException in case of error</span>
+<span class="source-line-no">119</span><span id="line-119">   */</span>
+<span class="source-line-no">120</span><span id="line-120">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
+<span class="source-line-no">121</span><span id="line-121">    String snapshotName, Scan scan, boolean snapshotAlreadyRestored) throws IOException {</span>
+<span class="source-line-no">122</span><span id="line-122">    this.conf = conf;</span>
+<span class="source-line-no">123</span><span id="line-123">    this.snapshotName = snapshotName;</span>
+<span class="source-line-no">124</span><span id="line-124">    this.rootDir = rootDir;</span>
+<span class="source-line-no">125</span><span id="line-125">    this.scan = scan;</span>
+<span class="source-line-no">126</span><span id="line-126">    this.snapshotAlreadyRestored = snapshotAlreadyRestored;</span>
+<span class="source-line-no">127</span><span id="line-127">    this.fs = rootDir.getFileSystem(conf);</span>
+<span class="source-line-no">128</span><span id="line-128">    conf.setBoolean(MemStoreLAB.USEMSLAB_KEY, false);</span>
+<span class="source-line-no">129</span><span id="line-129"></span>
+<span class="source-line-no">130</span><span id="line-130">    if (snapshotAlreadyRestored) {</span>
+<span class="source-line-no">131</span><span id="line-131">      this.restoreDir = restoreDir;</span>
+<span class="source-line-no">132</span><span id="line-132">      openWithoutRestoringSnapshot();</span>
+<span class="source-line-no">133</span><span id="line-133">    } else {</span>
+<span class="source-line-no">134</span><span id="line-134">      // restoreDir will be deleted in close(), use a unique sub directory</span>
+<span class="source-line-no">135</span><span id="line-135">      this.restoreDir = new Path(restoreDir, UUID.randomUUID().toString());</span>
+<span class="source-line-no">136</span><span id="line-136">      openWithRestoringSnapshot();</span>
+<span class="source-line-no">137</span><span id="line-137">    }</span>
+<span class="source-line-no">138</span><span id="line-138"></span>
+<span class="source-line-no">139</span><span id="line-139">    initScanMetrics(scan);</span>
+<span class="source-line-no">140</span><span id="line-140">  }</span>
+<span class="source-line-no">141</span><span id="line-141"></span>
+<span class="source-line-no">142</span><span id="line-142">  private void openWithoutRestoringSnapshot() throws IOException {</span>
+<span class="source-line-no">143</span><span id="line-143">    Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);</span>
+<span class="source-line-no">144</span><span id="line-144">    SnapshotProtos.SnapshotDescription snapshotDesc =</span>
+<span class="source-line-no">145</span><span id="line-145">      SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);</span>
+<span class="source-line-no">146</span><span id="line-146"></span>
+<span class="source-line-no">147</span><span id="line-147">    SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshotDesc);</span>
+<span class="source-line-no">148</span><span id="line-148">    List&lt;SnapshotRegionManifest&gt; regionManifests = manifest.getRegionManifests();</span>
+<span class="source-line-no">149</span><span id="line-149">    if (regionManifests == null) {</span>
+<span class="source-line-no">150</span><span id="line-150">      throw new IllegalArgumentException("Snapshot seems empty, snapshotName: " + snapshotName);</span>
+<span class="source-line-no">151</span><span id="line-151">    }</span>
+<span class="source-line-no">152</span><span id="line-152"></span>
+<span class="source-line-no">153</span><span id="line-153">    regions = new ArrayList&lt;&gt;(regionManifests.size());</span>
+<span class="source-line-no">154</span><span id="line-154">    regionManifests.stream().map(r -&gt; ProtobufUtil.toRegionInfo(r.getRegionInfo()))</span>
+<span class="source-line-no">155</span><span id="line-155">      .filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
+<span class="source-line-no">156</span><span id="line-156">    htd = manifest.getTableDescriptor();</span>
+<span class="source-line-no">157</span><span id="line-157">  }</span>
+<span class="source-line-no">158</span><span id="line-158"></span>
+<span class="source-line-no">159</span><span id="line-159">  private boolean isValidRegion(RegionInfo hri) {</span>
+<span class="source-line-no">160</span><span id="line-160">    // An offline split parent region should be excluded.</span>
+<span class="source-line-no">161</span><span id="line-161">    if (hri.isOffline() &amp;&amp; (hri.isSplit() || hri.isSplitParent())) {</span>
+<span class="source-line-no">162</span><span id="line-162">      return false;</span>
+<span class="source-line-no">163</span><span id="line-163">    }</span>
+<span class="source-line-no">164</span><span id="line-164">    // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
+<span class="source-line-no">165</span><span id="line-165">    // region directory under the table dir to open. See HBASE-30365 and HBASE-30368.</span>
+<span class="source-line-no">166</span><span id="line-166">    if (MobUtils.isMobRegionInfo(hri)) {</span>
+<span class="source-line-no">167</span><span id="line-167">      return false;</span>
+<span class="source-line-no">168</span><span id="line-168">    }</span>
+<span class="source-line-no">169</span><span id="line-169">    return PrivateCellUtil.overlappingKeys(scan.getStartRow(), scan.getStopRow(), hri.getStartKey(),</span>
+<span class="source-line-no">170</span><span id="line-170">      hri.getEndKey());</span>
+<span class="source-line-no">171</span><span id="line-171">  }</span>
+<span class="source-line-no">172</span><span id="line-172"></span>
+<span class="source-line-no">173</span><span id="line-173">  private void openWithRestoringSnapshot() throws IOException {</span>
+<span class="source-line-no">174</span><span id="line-174">    final RestoreSnapshotHelper.RestoreMetaChanges meta =</span>
+<span class="source-line-no">175</span><span id="line-175">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">176</span><span id="line-176">    final List&lt;RegionInfo&gt; restoredRegions = meta.getRegionsToAdd();</span>
+<span class="source-line-no">177</span><span id="line-177"></span>
+<span class="source-line-no">178</span><span id="line-178">    htd = meta.getTableDescriptor();</span>
+<span class="source-line-no">179</span><span id="line-179">    regions = new ArrayList&lt;&gt;(restoredRegions.size());</span>
+<span class="source-line-no">180</span><span id="line-180">    restoredRegions.stream().filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
+<span class="source-line-no">181</span><span id="line-181">  }</span>
+<span class="source-line-no">182</span><span id="line-182"></span>
+<span class="source-line-no">183</span><span id="line-183">  @Override</span>
+<span class="source-line-no">184</span><span id="line-184">  public Result next() throws IOException {</span>
+<span class="source-line-no">185</span><span id="line-185">    Result result = null;</span>
+<span class="source-line-no">186</span><span id="line-186">    while (true) {</span>
+<span class="source-line-no">187</span><span id="line-187">      if (currentRegionScanner == null) {</span>
+<span class="source-line-no">188</span><span id="line-188">        currentRegion++;</span>
+<span class="source-line-no">189</span><span id="line-189">        if (currentRegion &gt;= regions.size()) {</span>
+<span class="source-line-no">190</span><span id="line-190">          return null;</span>
+<span class="source-line-no">191</span><span id="line-191">        }</span>
+<span class="source-line-no">192</span><span id="line-192"></span>
+<span class="source-line-no">193</span><span id="line-193">        RegionInfo hri = regions.get(currentRegion);</span>
+<span class="source-line-no">194</span><span id="line-194">        currentRegionScanner =</span>
+<span class="source-line-no">195</span><span id="line-195">          new ClientSideRegionScanner(conf, fs, restoreDir, htd, hri, scan, scanMetrics);</span>
+<span class="source-line-no">196</span><span id="line-196">        if (this.scanMetrics != null) {</span>
+<span class="source-line-no">197</span><span id="line-197">          this.scanMetrics.addToCounter(ScanMetrics.REGIONS_SCANNED_METRIC_NAME, 1);</span>
+<span class="source-line-no">198</span><span id="line-198">        }</span>
+<span class="source-line-no">199</span><span id="line-199">      }</span>
+<span class="source-line-no">200</span><span id="line-200"></span>
+<span class="source-line-no">201</span><span id="line-201">      try {</span>
+<span class="source-line-no">202</span><span id="line-202">        result = currentRegionScanner.next();</span>
+<span class="source-line-no">203</span><span id="line-203">        if (result != null) {</span>
+<span class="source-line-no">204</span><span id="line-204">          if (scan.getLimit() &gt; 0 &amp;&amp; ++this.numOfCompleteRows &gt; scan.getLimit()) {</span>
+<span class="source-line-no">205</span><span id="line-205">            result = null;</span>
+<span class="source-line-no">206</span><span id="line-206">          }</span>
+<span class="source-line-no">207</span><span id="line-207">          return result;</span>
+<span class="source-line-no">208</span><span id="line-208">        }</span>
+<span class="source-line-no">209</span><span id="line-209">      } finally {</span>
+<span class="source-line-no">210</span><span id="line-210">        if (result == null) {</span>
+<span class="source-line-no">211</span><span id="line-211">          currentRegionScanner.close();</span>
+<span class="source-line-no">212</span><span id="line-212">          currentRegionScanner = null;</span>
+<span class="source-line-no">213</span><span id="line-213">        }</span>
+<span class="source-line-no">214</span><span id="line-214">      }</span>
+<span class="source-line-no">215</span><span id="line-215">    }</span>
+<span class="source-line-no">216</span><span id="line-216">  }</span>
+<span class="source-line-no">217</span><span id="line-217"></span>
+<span class="source-line-no">218</span><span id="line-218">  private void cleanup() {</span>
+<span class="source-line-no">219</span><span id="line-219">    try {</span>
+<span class="source-line-no">220</span><span id="line-220">      if (fs.exists(this.restoreDir)) {</span>
+<span class="source-line-no">221</span><span id="line-221">        if (!fs.delete(this.restoreDir, true)) {</span>
+<span class="source-line-no">222</span><span id="line-222">          LOG.warn(</span>
+<span class="source-line-no">223</span><span id="line-223">            "Delete restore directory for the snapshot failed. restoreDir: " + this.restoreDir);</span>
+<span class="source-line-no">224</span><span id="line-224">        }</span>
+<span class="source-line-no">225</span><span id="line-225">      }</span>
+<span class="source-line-no">226</span><span id="line-226">    } catch (IOException ex) {</span>
+<span class="source-line-no">227</span><span id="line-227">      LOG.warn(</span>
+<span class="source-line-no">228</span><span id="line-228">        "Could not delete restore directory for the snapshot. restoreDir: " + this.restoreDir, ex);</span>
+<span class="source-line-no">229</span><span id="line-229">    }</span>
+<span class="source-line-no">230</span><span id="line-230">  }</span>
+<span class="source-line-no">231</span><span id="line-231"></span>
+<span class="source-line-no">232</span><span id="line-232">  @Override</span>
+<span class="source-line-no">233</span><span id="line-233">  public void close() {</span>
+<span class="source-line-no">234</span><span id="line-234">    if (currentRegionScanner != null) {</span>
+<span class="source-line-no">235</span><span id="line-235">      currentRegionScanner.close();</span>
+<span class="source-line-no">236</span><span id="line-236">    }</span>
+<span class="source-line-no">237</span><span id="line-237">    // if snapshotAlreadyRestored is true, then we should invoke cleanup() method by hand.</span>
+<span class="source-line-no">238</span><span id="line-238">    if (!this.snapshotAlreadyRestored) {</span>
+<span class="source-line-no">239</span><span id="line-239">      cleanup();</span>
+<span class="source-line-no">240</span><span id="line-240">    }</span>
+<span class="source-line-no">241</span><span id="line-241">  }</span>
+<span class="source-line-no">242</span><span id="line-242"></span>
+<span class="source-line-no">243</span><span id="line-243">  @Override</span>
+<span class="source-line-no">244</span><span id="line-244">  public boolean renewLease() {</span>
+<span class="source-line-no">245</span><span id="line-245">    throw new UnsupportedOperationException();</span>
+<span class="source-line-no">246</span><span id="line-246">  }</span>
+<span class="source-line-no">247</span><span id="line-247"></span>
+<span class="source-line-no">248</span><span id="line-248">}</span>
 
 
 
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
index 4f25eecac2b..5d87836eb78 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
index 988b049b680..c9f4537ca7b 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
index ac564cc4ba2..8edc449b184 100644
--- a/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
+++ b/apidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/books/apache-hbase-reference-guide-dark-mode.pdf b/books/apache-hbase-reference-guide-dark-mode.pdf
index ad23ae19731..b19a4236fd7 100644
Binary files a/books/apache-hbase-reference-guide-dark-mode.pdf and b/books/apache-hbase-reference-guide-dark-mode.pdf differ
diff --git a/books/apache-hbase-reference-guide.pdf b/books/apache-hbase-reference-guide.pdf
index 44408ef21f6..ef62e2b1940 100644
Binary files a/books/apache-hbase-reference-guide.pdf and b/books/apache-hbase-reference-guide.pdf differ
diff --git a/checkstyle-aggregate.html b/checkstyle-aggregate.html
index da33538c277..f3ac404e867 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 2026-09-08
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-checkstyle-plugin:3.6.0:checkstyle-aggregate at 2026-09-09
  | Rendered using Apache Maven Fluido Skin 2.0.0-M9
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/dependency-convergence.html b/dependency-convergence.html
index b079abe4c5a..2ae791aa053 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 2026-09-08
+ | 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 2026-09-09
  | 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 b62fb46e634..57c7e53fd2e 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 2026-09-08
+ | 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 2026-09-09
  | 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 34582d3d809..a5ce0cd59cd 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 2026-09-08
+ | 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 2026-09-09
  | 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/client/TableSnapshotScanner.html b/devapidocs/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
index a4fb611424f..8fd5ed43bd1 100644
--- a/devapidocs/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
+++ b/devapidocs/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
@@ -84,7 +84,7 @@ loadScripts(document, 'script');</script>
 </dl>
 <hr>
 <div class="type-signature"><span class="annotations">@Private
-</span><span class="modifiers">public class </span><span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-65">TableSnapshotScanner</a></span>
+</span><span class="modifiers">public class </span><span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-66">TableSnapshotScanner</a></span>
 <span class="extends-implements">extends <a href="AbstractClientScanner.html" title="class in org.apache.hadoop.hbase.client">AbstractClientScanner</a></span></div>
 <div class="block">A Scanner which performs a scan over snapshot files. Using this class requires copying the
  snapshot to a temporary empty directory, which will copy the snapshot reference files into that
@@ -264,79 +264,79 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="LOG">
 <h3>LOG</h3>
-<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">org.slf4j.Logger</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-68">LOG</a></span></div>
+<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">org.slf4j.Logger</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-69">LOG</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="conf">
 <h3>conf</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.conf.Configuration</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-70">conf</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.conf.Configuration</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-71">conf</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="snapshotName">
 <h3>snapshotName</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-71">snapshotName</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-72">snapshotName</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="fs">
 <h3>fs</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.FileSystem</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-72">fs</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.FileSystem</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-73">fs</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="rootDir">
 <h3>rootDir</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-73">rootDir</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-74">rootDir</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="restoreDir">
 <h3>restoreDir</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-74">restoreDir</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-75">restoreDir</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="scan">
 <h3>scan</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-75">scan</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-76">scan</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="regions">
 <h3>regions</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ArrayList.html" title="class or interface in java.util" class="external-link">ArrayList</a>&lt;<a href="RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&gt;</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScan [...]
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ArrayList.html" title="class or interface in java.util" class="external-link">ArrayList</a>&lt;<a href="RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&gt;</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScan [...]
 </section>
 </li>
 <li>
 <section class="detail" id="htd">
 <h3>htd</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-77">htd</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="TableDescriptor.html" title="interface in org.apache.hadoop.hbase.client">TableDescriptor</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-78">htd</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="snapshotAlreadyRestored">
 <h3>snapshotAlreadyRestored</h3>
-<div class="member-signature"><span class="modifiers">private final</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-78">snapshotAlreadyRestored</a></span></div>
+<div class="member-signature"><span class="modifiers">private final</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-79">snapshotAlreadyRestored</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="currentRegionScanner">
 <h3>currentRegionScanner</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="ClientSideRegionScanner.html" title="class in org.apache.hadoop.hbase.client">ClientSideRegionScanner</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-80">currentRegionScanner</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="ClientSideRegionScanner.html" title="class in org.apache.hadoop.hbase.client">ClientSideRegionScanner</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-81">currentRegionScanner</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="currentRegion">
 <h3>currentRegion</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-81">currentRegion</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-82">currentRegion</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="numOfCompleteRows">
 <h3>numOfCompleteRows</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-83">numOfCompleteRows</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-84">numOfCompleteRows</a></span></div>
 </section>
 </li>
 </ul>
@@ -350,7 +350,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="&lt;init&gt;(org.apache.hadoop.conf.Configuration,org.apache.hadoop.fs.Path,java.lang.String,org.apache.hadoop.hbase.client.Scan)">
 <h3>TableSnapshotScanner</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-96">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-97">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
  org.apache.hadoop.fs.Path&nbsp;restoreDir,
  <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a>&nbsp;snapshotName,
  <a href="Scan.html" title="class in org.apache.hadoop.hbase.client">Scan</a>&nbsp;scan)</span>
@@ -373,7 +373,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="&lt;init&gt;(org.apache.hadoop.conf.Configuration,org.apache.hadoop.fs.Path,org.apache.hadoop.fs.Path,java.lang.String,org.apache.hadoop.hbase.client.Scan)">
 <h3>TableSnapshotScanner</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-101">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-102">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
  org.apache.hadoop.fs.Path&nbsp;rootDir,
  org.apache.hadoop.fs.Path&nbsp;restoreDir,
  <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a>&nbsp;snapshotName,
@@ -388,7 +388,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="&lt;init&gt;(org.apache.hadoop.conf.Configuration,org.apache.hadoop.fs.Path,org.apache.hadoop.fs.Path,java.lang.String,org.apache.hadoop.hbase.client.Scan,boolean)">
 <h3>TableSnapshotScanner</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-119">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-120">TableSnapshotScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf,
  org.apache.hadoop.fs.Path&nbsp;rootDir,
  org.apache.hadoop.fs.Path&nbsp;restoreDir,
  <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a>&nbsp;snapshotName,
@@ -423,7 +423,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="openWithoutRestoringSnapshot()">
 <h3>openWithoutRestoringSnapshot</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-141">openWithoutRestoringSnapshot</a></span>()
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-142">openWithoutRestoringSnapshot</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>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -434,13 +434,13 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="isValidRegion(org.apache.hadoop.hbase.client.RegionInfo)">
 <h3>isValidRegion</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-158">isValidRegion</a></span><wbr><span class="parameters">(<a href="RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;hri)</span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-159">isValidRegion</a></span><wbr><span class="parameters">(<a href="RegionInfo.html" title="interface in org.apache.hadoop.hbase.client">RegionInfo</a>&nbsp;hri)</span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="openWithRestoringSnapshot()">
 <h3>openWithRestoringSnapshot</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-167">openWithRestoringSnapshot</a></span>()
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-173">openWithRestoringSnapshot</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>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -451,7 +451,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="next()">
 <h3>next</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type"><a href="Result.html" title="class in org.apache.hadoop.hbase.client">Result</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-177">next</a></span>()
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type"><a href="Result.html" title="class in org.apache.hadoop.hbase.client">Result</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-183">next</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:&nbsp;<code><a href="ResultScanner.html#next()">ResultScanner</a></code></span></div>
 <div class="block">Grab the next row's worth of values. The scanner will return a Result.</div>
@@ -466,13 +466,13 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="cleanup()">
 <h3>cleanup</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-212">cleanup</a></span>()</div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-218">cleanup</a></span>()</div>
 </section>
 </li>
 <li>
 <section class="detail" id="close()">
 <h3>close</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-226">close</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-232">close</a></span>()</div>
 <div class="block"><span class="descfrm-type-label">Description copied from interface:&nbsp;<code><a href="ResultScanner.html#close()">ResultScanner</a></code></span></div>
 <div class="block">Closes the scanner and releases any resources it has allocated</div>
 </section>
@@ -480,7 +480,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="renewLease()">
 <h3>renewLease</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-237">renewLease</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html#line-243">renewLease</a></span>()</div>
 <div class="block"><span class="descfrm-type-label">Description copied from interface:&nbsp;<code><a href="ResultScanner.html#renewLease()">ResultScanner</a></code></span></div>
 <div class="block">Allow the client to renew the scanner's lease on the server.</div>
 <dl class="notes">
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html b/devapidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
index 9217df49239..5c7d1bfa0e1 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/client/TableSnapshotScanner.html
@@ -39,220 +39,226 @@
 <span class="source-line-no">026</span><span id="line-26">import org.apache.hadoop.fs.Path;</span>
 <span class="source-line-no">027</span><span id="line-27">import org.apache.hadoop.hbase.PrivateCellUtil;</span>
 <span class="source-line-no">028</span><span id="line-28">import org.apache.hadoop.hbase.client.metrics.ScanMetrics;</span>
-<span class="source-line-no">029</span><span id="line-29">import org.apache.hadoop.hbase.regionserver.MemStoreLAB;</span>
-<span class="source-line-no">030</span><span id="line-30">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
-<span class="source-line-no">031</span><span id="line-31">import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;</span>
-<span class="source-line-no">032</span><span id="line-32">import org.apache.hadoop.hbase.snapshot.SnapshotManifest;</span>
-<span class="source-line-no">033</span><span id="line-33">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
-<span class="source-line-no">034</span><span id="line-34">import org.apache.yetus.audience.InterfaceAudience;</span>
-<span class="source-line-no">035</span><span id="line-35">import org.slf4j.Logger;</span>
-<span class="source-line-no">036</span><span id="line-36">import org.slf4j.LoggerFactory;</span>
-<span class="source-line-no">037</span><span id="line-37"></span>
-<span class="source-line-no">038</span><span id="line-38">import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;</span>
-<span class="source-line-no">039</span><span id="line-39">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;</span>
-<span class="source-line-no">040</span><span id="line-40">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;</span>
-<span class="source-line-no">041</span><span id="line-41"></span>
-<span class="source-line-no">042</span><span id="line-42">/**</span>
-<span class="source-line-no">043</span><span id="line-43"> * A Scanner which performs a scan over snapshot files. Using this class requires copying the</span>
-<span class="source-line-no">044</span><span id="line-44"> * snapshot to a temporary empty directory, which will copy the snapshot reference files into that</span>
-<span class="source-line-no">045</span><span id="line-45"> * directory. Actual data files are not copied.</span>
-<span class="source-line-no">046</span><span id="line-46"> * &lt;p&gt;</span>
-<span class="source-line-no">047</span><span id="line-47"> * This also allows one to run the scan from an online or offline hbase cluster. The snapshot files</span>
-<span class="source-line-no">048</span><span id="line-48"> * can be exported by using the org.apache.hadoop.hbase.snapshot.ExportSnapshot tool, to a pure-hdfs</span>
-<span class="source-line-no">049</span><span id="line-49"> * cluster, and this scanner can be used to run the scan directly over the snapshot files. The</span>
-<span class="source-line-no">050</span><span id="line-50"> * snapshot should not be deleted while there are open scanners reading from snapshot files.</span>
-<span class="source-line-no">051</span><span id="line-51"> * &lt;p&gt;</span>
-<span class="source-line-no">052</span><span id="line-52"> * An internal RegionScanner is used to execute the {@link Scan} obtained from the user for each</span>
-<span class="source-line-no">053</span><span id="line-53"> * region in the snapshot.</span>
-<span class="source-line-no">054</span><span id="line-54"> * &lt;p&gt;</span>
-<span class="source-line-no">055</span><span id="line-55"> * HBase owns all the data and snapshot files on the filesystem. Only the HBase user can read from</span>
-<span class="source-line-no">056</span><span id="line-56"> * snapshot files and data files. HBase also enforces security because all the requests are handled</span>
-<span class="source-line-no">057</span><span id="line-57"> * by the server layer, and the user cannot read from the data files directly. To read from snapshot</span>
-<span class="source-line-no">058</span><span id="line-58"> * files directly from the file system, the user who is running the MR job must have sufficient</span>
-<span class="source-line-no">059</span><span id="line-59"> * permissions to access snapshot and reference files. This means that to run mapreduce over</span>
-<span class="source-line-no">060</span><span id="line-60"> * snapshot files, the job has to be run as the HBase user or the user must have group or other</span>
-<span class="source-line-no">061</span><span id="line-61"> * priviledges in the filesystem (See HBASE-8369). Note that, given other users access to read from</span>
-<span class="source-line-no">062</span><span id="line-62"> * snapshot/data files will completely circumvent the access control enforced by HBase. See</span>
-<span class="source-line-no">063</span><span id="line-63"> * org.apache.hadoop.hbase.mapreduce.TableSnapshotInputFormat.</span>
-<span class="source-line-no">064</span><span id="line-64"> */</span>
-<span class="source-line-no">065</span><span id="line-65">@InterfaceAudience.Private</span>
-<span class="source-line-no">066</span><span id="line-66">public class TableSnapshotScanner extends AbstractClientScanner {</span>
-<span class="source-line-no">067</span><span id="line-67"></span>
-<span class="source-line-no">068</span><span id="line-68">  private static final Logger LOG = LoggerFactory.getLogger(TableSnapshotScanner.class);</span>
-<span class="source-line-no">069</span><span id="line-69"></span>
-<span class="source-line-no">070</span><span id="line-70">  private Configuration conf;</span>
-<span class="source-line-no">071</span><span id="line-71">  private String snapshotName;</span>
-<span class="source-line-no">072</span><span id="line-72">  private FileSystem fs;</span>
-<span class="source-line-no">073</span><span id="line-73">  private Path rootDir;</span>
-<span class="source-line-no">074</span><span id="line-74">  private Path restoreDir;</span>
-<span class="source-line-no">075</span><span id="line-75">  private Scan scan;</span>
-<span class="source-line-no">076</span><span id="line-76">  private ArrayList&lt;RegionInfo&gt; regions;</span>
-<span class="source-line-no">077</span><span id="line-77">  private TableDescriptor htd;</span>
-<span class="source-line-no">078</span><span id="line-78">  private final boolean snapshotAlreadyRestored;</span>
-<span class="source-line-no">079</span><span id="line-79"></span>
-<span class="source-line-no">080</span><span id="line-80">  private ClientSideRegionScanner currentRegionScanner = null;</span>
-<span class="source-line-no">081</span><span id="line-81">  private int currentRegion = -1;</span>
-<span class="source-line-no">082</span><span id="line-82"></span>
-<span class="source-line-no">083</span><span id="line-83">  private int numOfCompleteRows = 0;</span>
-<span class="source-line-no">084</span><span id="line-84"></span>
-<span class="source-line-no">085</span><span id="line-85">  /**</span>
-<span class="source-line-no">086</span><span id="line-86">   * Creates a TableSnapshotScanner.</span>
-<span class="source-line-no">087</span><span id="line-87">   * @param conf         the configuration</span>
-<span class="source-line-no">088</span><span id="line-88">   * @param restoreDir   a temporary directory to copy the snapshot files into. Current user should</span>
-<span class="source-line-no">089</span><span id="line-89">   *                     have write permissions to this directory, and this should not be a</span>
-<span class="source-line-no">090</span><span id="line-90">   *                     subdirectory of rootDir. The scanner deletes the contents of the directory</span>
-<span class="source-line-no">091</span><span id="line-91">   *                     once the scanner is closed.</span>
-<span class="source-line-no">092</span><span id="line-92">   * @param snapshotName the name of the snapshot to read from</span>
-<span class="source-line-no">093</span><span id="line-93">   * @param scan         a Scan representing scan parameters</span>
-<span class="source-line-no">094</span><span id="line-94">   * @throws IOException in case of error</span>
-<span class="source-line-no">095</span><span id="line-95">   */</span>
-<span class="source-line-no">096</span><span id="line-96">  public TableSnapshotScanner(Configuration conf, Path restoreDir, String snapshotName, Scan scan)</span>
-<span class="source-line-no">097</span><span id="line-97">    throws IOException {</span>
-<span class="source-line-no">098</span><span id="line-98">    this(conf, CommonFSUtils.getRootDir(conf), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">099</span><span id="line-99">  }</span>
-<span class="source-line-no">100</span><span id="line-100"></span>
-<span class="source-line-no">101</span><span id="line-101">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
-<span class="source-line-no">102</span><span id="line-102">    String snapshotName, Scan scan) throws IOException {</span>
-<span class="source-line-no">103</span><span id="line-103">    this(conf, rootDir, restoreDir, snapshotName, scan, false);</span>
-<span class="source-line-no">104</span><span id="line-104">  }</span>
-<span class="source-line-no">105</span><span id="line-105"></span>
-<span class="source-line-no">106</span><span id="line-106">  /**</span>
-<span class="source-line-no">107</span><span id="line-107">   * Creates a TableSnapshotScanner.</span>
-<span class="source-line-no">108</span><span id="line-108">   * @param conf                    the configuration</span>
-<span class="source-line-no">109</span><span id="line-109">   * @param rootDir                 root directory for HBase.</span>
-<span class="source-line-no">110</span><span id="line-110">   * @param restoreDir              a temporary directory to copy the snapshot files into. Current</span>
-<span class="source-line-no">111</span><span id="line-111">   *                                user should have write permissions to this directory, and this</span>
-<span class="source-line-no">112</span><span id="line-112">   *                                should not be a subdirectory of rootdir. The scanner deletes the</span>
-<span class="source-line-no">113</span><span id="line-113">   *                                contents of the directory once the scanner is closed.</span>
-<span class="source-line-no">114</span><span id="line-114">   * @param snapshotName            the name of the snapshot to read from</span>
-<span class="source-line-no">115</span><span id="line-115">   * @param scan                    a Scan representing scan parameters</span>
-<span class="source-line-no">116</span><span id="line-116">   * @param snapshotAlreadyRestored true to indicate that snapshot has been restored.</span>
-<span class="source-line-no">117</span><span id="line-117">   * @throws IOException in case of error</span>
-<span class="source-line-no">118</span><span id="line-118">   */</span>
-<span class="source-line-no">119</span><span id="line-119">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
-<span class="source-line-no">120</span><span id="line-120">    String snapshotName, Scan scan, boolean snapshotAlreadyRestored) throws IOException {</span>
-<span class="source-line-no">121</span><span id="line-121">    this.conf = conf;</span>
-<span class="source-line-no">122</span><span id="line-122">    this.snapshotName = snapshotName;</span>
-<span class="source-line-no">123</span><span id="line-123">    this.rootDir = rootDir;</span>
-<span class="source-line-no">124</span><span id="line-124">    this.scan = scan;</span>
-<span class="source-line-no">125</span><span id="line-125">    this.snapshotAlreadyRestored = snapshotAlreadyRestored;</span>
-<span class="source-line-no">126</span><span id="line-126">    this.fs = rootDir.getFileSystem(conf);</span>
-<span class="source-line-no">127</span><span id="line-127">    conf.setBoolean(MemStoreLAB.USEMSLAB_KEY, false);</span>
-<span class="source-line-no">128</span><span id="line-128"></span>
-<span class="source-line-no">129</span><span id="line-129">    if (snapshotAlreadyRestored) {</span>
-<span class="source-line-no">130</span><span id="line-130">      this.restoreDir = restoreDir;</span>
-<span class="source-line-no">131</span><span id="line-131">      openWithoutRestoringSnapshot();</span>
-<span class="source-line-no">132</span><span id="line-132">    } else {</span>
-<span class="source-line-no">133</span><span id="line-133">      // restoreDir will be deleted in close(), use a unique sub directory</span>
-<span class="source-line-no">134</span><span id="line-134">      this.restoreDir = new Path(restoreDir, UUID.randomUUID().toString());</span>
-<span class="source-line-no">135</span><span id="line-135">      openWithRestoringSnapshot();</span>
-<span class="source-line-no">136</span><span id="line-136">    }</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">    initScanMetrics(scan);</span>
-<span class="source-line-no">139</span><span id="line-139">  }</span>
-<span class="source-line-no">140</span><span id="line-140"></span>
-<span class="source-line-no">141</span><span id="line-141">  private void openWithoutRestoringSnapshot() throws IOException {</span>
-<span class="source-line-no">142</span><span id="line-142">    Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);</span>
-<span class="source-line-no">143</span><span id="line-143">    SnapshotProtos.SnapshotDescription snapshotDesc =</span>
-<span class="source-line-no">144</span><span id="line-144">      SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);</span>
-<span class="source-line-no">145</span><span id="line-145"></span>
-<span class="source-line-no">146</span><span id="line-146">    SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshotDesc);</span>
-<span class="source-line-no">147</span><span id="line-147">    List&lt;SnapshotRegionManifest&gt; regionManifests = manifest.getRegionManifests();</span>
-<span class="source-line-no">148</span><span id="line-148">    if (regionManifests == null) {</span>
-<span class="source-line-no">149</span><span id="line-149">      throw new IllegalArgumentException("Snapshot seems empty, snapshotName: " + snapshotName);</span>
-<span class="source-line-no">150</span><span id="line-150">    }</span>
-<span class="source-line-no">151</span><span id="line-151"></span>
-<span class="source-line-no">152</span><span id="line-152">    regions = new ArrayList&lt;&gt;(regionManifests.size());</span>
-<span class="source-line-no">153</span><span id="line-153">    regionManifests.stream().map(r -&gt; ProtobufUtil.toRegionInfo(r.getRegionInfo()))</span>
-<span class="source-line-no">154</span><span id="line-154">      .filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
-<span class="source-line-no">155</span><span id="line-155">    htd = manifest.getTableDescriptor();</span>
-<span class="source-line-no">156</span><span id="line-156">  }</span>
-<span class="source-line-no">157</span><span id="line-157"></span>
-<span class="source-line-no">158</span><span id="line-158">  private boolean isValidRegion(RegionInfo hri) {</span>
-<span class="source-line-no">159</span><span id="line-159">    // An offline split parent region should be excluded.</span>
-<span class="source-line-no">160</span><span id="line-160">    if (hri.isOffline() &amp;&amp; (hri.isSplit() || hri.isSplitParent())) {</span>
-<span class="source-line-no">161</span><span id="line-161">      return false;</span>
-<span class="source-line-no">162</span><span id="line-162">    }</span>
-<span class="source-line-no">163</span><span id="line-163">    return PrivateCellUtil.overlappingKeys(scan.getStartRow(), scan.getStopRow(), hri.getStartKey(),</span>
-<span class="source-line-no">164</span><span id="line-164">      hri.getEndKey());</span>
-<span class="source-line-no">165</span><span id="line-165">  }</span>
-<span class="source-line-no">166</span><span id="line-166"></span>
-<span class="source-line-no">167</span><span id="line-167">  private void openWithRestoringSnapshot() throws IOException {</span>
-<span class="source-line-no">168</span><span id="line-168">    final RestoreSnapshotHelper.RestoreMetaChanges meta =</span>
-<span class="source-line-no">169</span><span id="line-169">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">170</span><span id="line-170">    final List&lt;RegionInfo&gt; restoredRegions = meta.getRegionsToAdd();</span>
-<span class="source-line-no">171</span><span id="line-171"></span>
-<span class="source-line-no">172</span><span id="line-172">    htd = meta.getTableDescriptor();</span>
-<span class="source-line-no">173</span><span id="line-173">    regions = new ArrayList&lt;&gt;(restoredRegions.size());</span>
-<span class="source-line-no">174</span><span id="line-174">    restoredRegions.stream().filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
-<span class="source-line-no">175</span><span id="line-175">  }</span>
-<span class="source-line-no">176</span><span id="line-176"></span>
-<span class="source-line-no">177</span><span id="line-177">  @Override</span>
-<span class="source-line-no">178</span><span id="line-178">  public Result next() throws IOException {</span>
-<span class="source-line-no">179</span><span id="line-179">    Result result = null;</span>
-<span class="source-line-no">180</span><span id="line-180">    while (true) {</span>
-<span class="source-line-no">181</span><span id="line-181">      if (currentRegionScanner == null) {</span>
-<span class="source-line-no">182</span><span id="line-182">        currentRegion++;</span>
-<span class="source-line-no">183</span><span id="line-183">        if (currentRegion &gt;= regions.size()) {</span>
-<span class="source-line-no">184</span><span id="line-184">          return null;</span>
-<span class="source-line-no">185</span><span id="line-185">        }</span>
-<span class="source-line-no">186</span><span id="line-186"></span>
-<span class="source-line-no">187</span><span id="line-187">        RegionInfo hri = regions.get(currentRegion);</span>
-<span class="source-line-no">188</span><span id="line-188">        currentRegionScanner =</span>
-<span class="source-line-no">189</span><span id="line-189">          new ClientSideRegionScanner(conf, fs, restoreDir, htd, hri, scan, scanMetrics);</span>
-<span class="source-line-no">190</span><span id="line-190">        if (this.scanMetrics != null) {</span>
-<span class="source-line-no">191</span><span id="line-191">          this.scanMetrics.addToCounter(ScanMetrics.REGIONS_SCANNED_METRIC_NAME, 1);</span>
-<span class="source-line-no">192</span><span id="line-192">        }</span>
-<span class="source-line-no">193</span><span id="line-193">      }</span>
-<span class="source-line-no">194</span><span id="line-194"></span>
-<span class="source-line-no">195</span><span id="line-195">      try {</span>
-<span class="source-line-no">196</span><span id="line-196">        result = currentRegionScanner.next();</span>
-<span class="source-line-no">197</span><span id="line-197">        if (result != null) {</span>
-<span class="source-line-no">198</span><span id="line-198">          if (scan.getLimit() &gt; 0 &amp;&amp; ++this.numOfCompleteRows &gt; scan.getLimit()) {</span>
-<span class="source-line-no">199</span><span id="line-199">            result = null;</span>
-<span class="source-line-no">200</span><span id="line-200">          }</span>
-<span class="source-line-no">201</span><span id="line-201">          return result;</span>
-<span class="source-line-no">202</span><span id="line-202">        }</span>
-<span class="source-line-no">203</span><span id="line-203">      } finally {</span>
-<span class="source-line-no">204</span><span id="line-204">        if (result == null) {</span>
-<span class="source-line-no">205</span><span id="line-205">          currentRegionScanner.close();</span>
-<span class="source-line-no">206</span><span id="line-206">          currentRegionScanner = null;</span>
-<span class="source-line-no">207</span><span id="line-207">        }</span>
-<span class="source-line-no">208</span><span id="line-208">      }</span>
-<span class="source-line-no">209</span><span id="line-209">    }</span>
-<span class="source-line-no">210</span><span id="line-210">  }</span>
-<span class="source-line-no">211</span><span id="line-211"></span>
-<span class="source-line-no">212</span><span id="line-212">  private void cleanup() {</span>
-<span class="source-line-no">213</span><span id="line-213">    try {</span>
-<span class="source-line-no">214</span><span id="line-214">      if (fs.exists(this.restoreDir)) {</span>
-<span class="source-line-no">215</span><span id="line-215">        if (!fs.delete(this.restoreDir, true)) {</span>
-<span class="source-line-no">216</span><span id="line-216">          LOG.warn(</span>
-<span class="source-line-no">217</span><span id="line-217">            "Delete restore directory for the snapshot failed. restoreDir: " + this.restoreDir);</span>
-<span class="source-line-no">218</span><span id="line-218">        }</span>
-<span class="source-line-no">219</span><span id="line-219">      }</span>
-<span class="source-line-no">220</span><span id="line-220">    } catch (IOException ex) {</span>
-<span class="source-line-no">221</span><span id="line-221">      LOG.warn(</span>
-<span class="source-line-no">222</span><span id="line-222">        "Could not delete restore directory for the snapshot. restoreDir: " + this.restoreDir, ex);</span>
-<span class="source-line-no">223</span><span id="line-223">    }</span>
-<span class="source-line-no">224</span><span id="line-224">  }</span>
-<span class="source-line-no">225</span><span id="line-225"></span>
-<span class="source-line-no">226</span><span id="line-226">  @Override</span>
-<span class="source-line-no">227</span><span id="line-227">  public void close() {</span>
-<span class="source-line-no">228</span><span id="line-228">    if (currentRegionScanner != null) {</span>
-<span class="source-line-no">229</span><span id="line-229">      currentRegionScanner.close();</span>
-<span class="source-line-no">230</span><span id="line-230">    }</span>
-<span class="source-line-no">231</span><span id="line-231">    // if snapshotAlreadyRestored is true, then we should invoke cleanup() method by hand.</span>
-<span class="source-line-no">232</span><span id="line-232">    if (!this.snapshotAlreadyRestored) {</span>
-<span class="source-line-no">233</span><span id="line-233">      cleanup();</span>
-<span class="source-line-no">234</span><span id="line-234">    }</span>
-<span class="source-line-no">235</span><span id="line-235">  }</span>
-<span class="source-line-no">236</span><span id="line-236"></span>
-<span class="source-line-no">237</span><span id="line-237">  @Override</span>
-<span class="source-line-no">238</span><span id="line-238">  public boolean renewLease() {</span>
-<span class="source-line-no">239</span><span id="line-239">    throw new UnsupportedOperationException();</span>
-<span class="source-line-no">240</span><span id="line-240">  }</span>
-<span class="source-line-no">241</span><span id="line-241"></span>
-<span class="source-line-no">242</span><span id="line-242">}</span>
+<span class="source-line-no">029</span><span id="line-29">import org.apache.hadoop.hbase.mob.MobUtils;</span>
+<span class="source-line-no">030</span><span id="line-30">import org.apache.hadoop.hbase.regionserver.MemStoreLAB;</span>
+<span class="source-line-no">031</span><span id="line-31">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
+<span class="source-line-no">032</span><span id="line-32">import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;</span>
+<span class="source-line-no">033</span><span id="line-33">import org.apache.hadoop.hbase.snapshot.SnapshotManifest;</span>
+<span class="source-line-no">034</span><span id="line-34">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
+<span class="source-line-no">035</span><span id="line-35">import org.apache.yetus.audience.InterfaceAudience;</span>
+<span class="source-line-no">036</span><span id="line-36">import org.slf4j.Logger;</span>
+<span class="source-line-no">037</span><span id="line-37">import org.slf4j.LoggerFactory;</span>
+<span class="source-line-no">038</span><span id="line-38"></span>
+<span class="source-line-no">039</span><span id="line-39">import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;</span>
+<span class="source-line-no">040</span><span id="line-40">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;</span>
+<span class="source-line-no">041</span><span id="line-41">import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;</span>
+<span class="source-line-no">042</span><span id="line-42"></span>
+<span class="source-line-no">043</span><span id="line-43">/**</span>
+<span class="source-line-no">044</span><span id="line-44"> * A Scanner which performs a scan over snapshot files. Using this class requires copying the</span>
+<span class="source-line-no">045</span><span id="line-45"> * snapshot to a temporary empty directory, which will copy the snapshot reference files into that</span>
+<span class="source-line-no">046</span><span id="line-46"> * directory. Actual data files are not copied.</span>
+<span class="source-line-no">047</span><span id="line-47"> * &lt;p&gt;</span>
+<span class="source-line-no">048</span><span id="line-48"> * This also allows one to run the scan from an online or offline hbase cluster. The snapshot files</span>
+<span class="source-line-no">049</span><span id="line-49"> * can be exported by using the org.apache.hadoop.hbase.snapshot.ExportSnapshot tool, to a pure-hdfs</span>
+<span class="source-line-no">050</span><span id="line-50"> * cluster, and this scanner can be used to run the scan directly over the snapshot files. The</span>
+<span class="source-line-no">051</span><span id="line-51"> * snapshot should not be deleted while there are open scanners reading from snapshot files.</span>
+<span class="source-line-no">052</span><span id="line-52"> * &lt;p&gt;</span>
+<span class="source-line-no">053</span><span id="line-53"> * An internal RegionScanner is used to execute the {@link Scan} obtained from the user for each</span>
+<span class="source-line-no">054</span><span id="line-54"> * region in the snapshot.</span>
+<span class="source-line-no">055</span><span id="line-55"> * &lt;p&gt;</span>
+<span class="source-line-no">056</span><span id="line-56"> * HBase owns all the data and snapshot files on the filesystem. Only the HBase user can read from</span>
+<span class="source-line-no">057</span><span id="line-57"> * snapshot files and data files. HBase also enforces security because all the requests are handled</span>
+<span class="source-line-no">058</span><span id="line-58"> * by the server layer, and the user cannot read from the data files directly. To read from snapshot</span>
+<span class="source-line-no">059</span><span id="line-59"> * files directly from the file system, the user who is running the MR job must have sufficient</span>
+<span class="source-line-no">060</span><span id="line-60"> * permissions to access snapshot and reference files. This means that to run mapreduce over</span>
+<span class="source-line-no">061</span><span id="line-61"> * snapshot files, the job has to be run as the HBase user or the user must have group or other</span>
+<span class="source-line-no">062</span><span id="line-62"> * priviledges in the filesystem (See HBASE-8369). Note that, given other users access to read from</span>
+<span class="source-line-no">063</span><span id="line-63"> * snapshot/data files will completely circumvent the access control enforced by HBase. See</span>
+<span class="source-line-no">064</span><span id="line-64"> * org.apache.hadoop.hbase.mapreduce.TableSnapshotInputFormat.</span>
+<span class="source-line-no">065</span><span id="line-65"> */</span>
+<span class="source-line-no">066</span><span id="line-66">@InterfaceAudience.Private</span>
+<span class="source-line-no">067</span><span id="line-67">public class TableSnapshotScanner extends AbstractClientScanner {</span>
+<span class="source-line-no">068</span><span id="line-68"></span>
+<span class="source-line-no">069</span><span id="line-69">  private static final Logger LOG = LoggerFactory.getLogger(TableSnapshotScanner.class);</span>
+<span class="source-line-no">070</span><span id="line-70"></span>
+<span class="source-line-no">071</span><span id="line-71">  private Configuration conf;</span>
+<span class="source-line-no">072</span><span id="line-72">  private String snapshotName;</span>
+<span class="source-line-no">073</span><span id="line-73">  private FileSystem fs;</span>
+<span class="source-line-no">074</span><span id="line-74">  private Path rootDir;</span>
+<span class="source-line-no">075</span><span id="line-75">  private Path restoreDir;</span>
+<span class="source-line-no">076</span><span id="line-76">  private Scan scan;</span>
+<span class="source-line-no">077</span><span id="line-77">  private ArrayList&lt;RegionInfo&gt; regions;</span>
+<span class="source-line-no">078</span><span id="line-78">  private TableDescriptor htd;</span>
+<span class="source-line-no">079</span><span id="line-79">  private final boolean snapshotAlreadyRestored;</span>
+<span class="source-line-no">080</span><span id="line-80"></span>
+<span class="source-line-no">081</span><span id="line-81">  private ClientSideRegionScanner currentRegionScanner = null;</span>
+<span class="source-line-no">082</span><span id="line-82">  private int currentRegion = -1;</span>
+<span class="source-line-no">083</span><span id="line-83"></span>
+<span class="source-line-no">084</span><span id="line-84">  private int numOfCompleteRows = 0;</span>
+<span class="source-line-no">085</span><span id="line-85"></span>
+<span class="source-line-no">086</span><span id="line-86">  /**</span>
+<span class="source-line-no">087</span><span id="line-87">   * Creates a TableSnapshotScanner.</span>
+<span class="source-line-no">088</span><span id="line-88">   * @param conf         the configuration</span>
+<span class="source-line-no">089</span><span id="line-89">   * @param restoreDir   a temporary directory to copy the snapshot files into. Current user should</span>
+<span class="source-line-no">090</span><span id="line-90">   *                     have write permissions to this directory, and this should not be a</span>
+<span class="source-line-no">091</span><span id="line-91">   *                     subdirectory of rootDir. The scanner deletes the contents of the directory</span>
+<span class="source-line-no">092</span><span id="line-92">   *                     once the scanner is closed.</span>
+<span class="source-line-no">093</span><span id="line-93">   * @param snapshotName the name of the snapshot to read from</span>
+<span class="source-line-no">094</span><span id="line-94">   * @param scan         a Scan representing scan parameters</span>
+<span class="source-line-no">095</span><span id="line-95">   * @throws IOException in case of error</span>
+<span class="source-line-no">096</span><span id="line-96">   */</span>
+<span class="source-line-no">097</span><span id="line-97">  public TableSnapshotScanner(Configuration conf, Path restoreDir, String snapshotName, Scan scan)</span>
+<span class="source-line-no">098</span><span id="line-98">    throws IOException {</span>
+<span class="source-line-no">099</span><span id="line-99">    this(conf, CommonFSUtils.getRootDir(conf), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">100</span><span id="line-100">  }</span>
+<span class="source-line-no">101</span><span id="line-101"></span>
+<span class="source-line-no">102</span><span id="line-102">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
+<span class="source-line-no">103</span><span id="line-103">    String snapshotName, Scan scan) throws IOException {</span>
+<span class="source-line-no">104</span><span id="line-104">    this(conf, rootDir, restoreDir, snapshotName, scan, false);</span>
+<span class="source-line-no">105</span><span id="line-105">  }</span>
+<span class="source-line-no">106</span><span id="line-106"></span>
+<span class="source-line-no">107</span><span id="line-107">  /**</span>
+<span class="source-line-no">108</span><span id="line-108">   * Creates a TableSnapshotScanner.</span>
+<span class="source-line-no">109</span><span id="line-109">   * @param conf                    the configuration</span>
+<span class="source-line-no">110</span><span id="line-110">   * @param rootDir                 root directory for HBase.</span>
+<span class="source-line-no">111</span><span id="line-111">   * @param restoreDir              a temporary directory to copy the snapshot files into. Current</span>
+<span class="source-line-no">112</span><span id="line-112">   *                                user should have write permissions to this directory, and this</span>
+<span class="source-line-no">113</span><span id="line-113">   *                                should not be a subdirectory of rootdir. The scanner deletes the</span>
+<span class="source-line-no">114</span><span id="line-114">   *                                contents of the directory once the scanner is closed.</span>
+<span class="source-line-no">115</span><span id="line-115">   * @param snapshotName            the name of the snapshot to read from</span>
+<span class="source-line-no">116</span><span id="line-116">   * @param scan                    a Scan representing scan parameters</span>
+<span class="source-line-no">117</span><span id="line-117">   * @param snapshotAlreadyRestored true to indicate that snapshot has been restored.</span>
+<span class="source-line-no">118</span><span id="line-118">   * @throws IOException in case of error</span>
+<span class="source-line-no">119</span><span id="line-119">   */</span>
+<span class="source-line-no">120</span><span id="line-120">  public TableSnapshotScanner(Configuration conf, Path rootDir, Path restoreDir,</span>
+<span class="source-line-no">121</span><span id="line-121">    String snapshotName, Scan scan, boolean snapshotAlreadyRestored) throws IOException {</span>
+<span class="source-line-no">122</span><span id="line-122">    this.conf = conf;</span>
+<span class="source-line-no">123</span><span id="line-123">    this.snapshotName = snapshotName;</span>
+<span class="source-line-no">124</span><span id="line-124">    this.rootDir = rootDir;</span>
+<span class="source-line-no">125</span><span id="line-125">    this.scan = scan;</span>
+<span class="source-line-no">126</span><span id="line-126">    this.snapshotAlreadyRestored = snapshotAlreadyRestored;</span>
+<span class="source-line-no">127</span><span id="line-127">    this.fs = rootDir.getFileSystem(conf);</span>
+<span class="source-line-no">128</span><span id="line-128">    conf.setBoolean(MemStoreLAB.USEMSLAB_KEY, false);</span>
+<span class="source-line-no">129</span><span id="line-129"></span>
+<span class="source-line-no">130</span><span id="line-130">    if (snapshotAlreadyRestored) {</span>
+<span class="source-line-no">131</span><span id="line-131">      this.restoreDir = restoreDir;</span>
+<span class="source-line-no">132</span><span id="line-132">      openWithoutRestoringSnapshot();</span>
+<span class="source-line-no">133</span><span id="line-133">    } else {</span>
+<span class="source-line-no">134</span><span id="line-134">      // restoreDir will be deleted in close(), use a unique sub directory</span>
+<span class="source-line-no">135</span><span id="line-135">      this.restoreDir = new Path(restoreDir, UUID.randomUUID().toString());</span>
+<span class="source-line-no">136</span><span id="line-136">      openWithRestoringSnapshot();</span>
+<span class="source-line-no">137</span><span id="line-137">    }</span>
+<span class="source-line-no">138</span><span id="line-138"></span>
+<span class="source-line-no">139</span><span id="line-139">    initScanMetrics(scan);</span>
+<span class="source-line-no">140</span><span id="line-140">  }</span>
+<span class="source-line-no">141</span><span id="line-141"></span>
+<span class="source-line-no">142</span><span id="line-142">  private void openWithoutRestoringSnapshot() throws IOException {</span>
+<span class="source-line-no">143</span><span id="line-143">    Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);</span>
+<span class="source-line-no">144</span><span id="line-144">    SnapshotProtos.SnapshotDescription snapshotDesc =</span>
+<span class="source-line-no">145</span><span id="line-145">      SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);</span>
+<span class="source-line-no">146</span><span id="line-146"></span>
+<span class="source-line-no">147</span><span id="line-147">    SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshotDesc);</span>
+<span class="source-line-no">148</span><span id="line-148">    List&lt;SnapshotRegionManifest&gt; regionManifests = manifest.getRegionManifests();</span>
+<span class="source-line-no">149</span><span id="line-149">    if (regionManifests == null) {</span>
+<span class="source-line-no">150</span><span id="line-150">      throw new IllegalArgumentException("Snapshot seems empty, snapshotName: " + snapshotName);</span>
+<span class="source-line-no">151</span><span id="line-151">    }</span>
+<span class="source-line-no">152</span><span id="line-152"></span>
+<span class="source-line-no">153</span><span id="line-153">    regions = new ArrayList&lt;&gt;(regionManifests.size());</span>
+<span class="source-line-no">154</span><span id="line-154">    regionManifests.stream().map(r -&gt; ProtobufUtil.toRegionInfo(r.getRegionInfo()))</span>
+<span class="source-line-no">155</span><span id="line-155">      .filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
+<span class="source-line-no">156</span><span id="line-156">    htd = manifest.getTableDescriptor();</span>
+<span class="source-line-no">157</span><span id="line-157">  }</span>
+<span class="source-line-no">158</span><span id="line-158"></span>
+<span class="source-line-no">159</span><span id="line-159">  private boolean isValidRegion(RegionInfo hri) {</span>
+<span class="source-line-no">160</span><span id="line-160">    // An offline split parent region should be excluded.</span>
+<span class="source-line-no">161</span><span id="line-161">    if (hri.isOffline() &amp;&amp; (hri.isSplit() || hri.isSplitParent())) {</span>
+<span class="source-line-no">162</span><span id="line-162">      return false;</span>
+<span class="source-line-no">163</span><span id="line-163">    }</span>
+<span class="source-line-no">164</span><span id="line-164">    // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
+<span class="source-line-no">165</span><span id="line-165">    // region directory under the table dir to open. See HBASE-30365 and HBASE-30368.</span>
+<span class="source-line-no">166</span><span id="line-166">    if (MobUtils.isMobRegionInfo(hri)) {</span>
+<span class="source-line-no">167</span><span id="line-167">      return false;</span>
+<span class="source-line-no">168</span><span id="line-168">    }</span>
+<span class="source-line-no">169</span><span id="line-169">    return PrivateCellUtil.overlappingKeys(scan.getStartRow(), scan.getStopRow(), hri.getStartKey(),</span>
+<span class="source-line-no">170</span><span id="line-170">      hri.getEndKey());</span>
+<span class="source-line-no">171</span><span id="line-171">  }</span>
+<span class="source-line-no">172</span><span id="line-172"></span>
+<span class="source-line-no">173</span><span id="line-173">  private void openWithRestoringSnapshot() throws IOException {</span>
+<span class="source-line-no">174</span><span id="line-174">    final RestoreSnapshotHelper.RestoreMetaChanges meta =</span>
+<span class="source-line-no">175</span><span id="line-175">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">176</span><span id="line-176">    final List&lt;RegionInfo&gt; restoredRegions = meta.getRegionsToAdd();</span>
+<span class="source-line-no">177</span><span id="line-177"></span>
+<span class="source-line-no">178</span><span id="line-178">    htd = meta.getTableDescriptor();</span>
+<span class="source-line-no">179</span><span id="line-179">    regions = new ArrayList&lt;&gt;(restoredRegions.size());</span>
+<span class="source-line-no">180</span><span id="line-180">    restoredRegions.stream().filter(this::isValidRegion).sorted().forEach(r -&gt; regions.add(r));</span>
+<span class="source-line-no">181</span><span id="line-181">  }</span>
+<span class="source-line-no">182</span><span id="line-182"></span>
+<span class="source-line-no">183</span><span id="line-183">  @Override</span>
+<span class="source-line-no">184</span><span id="line-184">  public Result next() throws IOException {</span>
+<span class="source-line-no">185</span><span id="line-185">    Result result = null;</span>
+<span class="source-line-no">186</span><span id="line-186">    while (true) {</span>
+<span class="source-line-no">187</span><span id="line-187">      if (currentRegionScanner == null) {</span>
+<span class="source-line-no">188</span><span id="line-188">        currentRegion++;</span>
+<span class="source-line-no">189</span><span id="line-189">        if (currentRegion &gt;= regions.size()) {</span>
+<span class="source-line-no">190</span><span id="line-190">          return null;</span>
+<span class="source-line-no">191</span><span id="line-191">        }</span>
+<span class="source-line-no">192</span><span id="line-192"></span>
+<span class="source-line-no">193</span><span id="line-193">        RegionInfo hri = regions.get(currentRegion);</span>
+<span class="source-line-no">194</span><span id="line-194">        currentRegionScanner =</span>
+<span class="source-line-no">195</span><span id="line-195">          new ClientSideRegionScanner(conf, fs, restoreDir, htd, hri, scan, scanMetrics);</span>
+<span class="source-line-no">196</span><span id="line-196">        if (this.scanMetrics != null) {</span>
+<span class="source-line-no">197</span><span id="line-197">          this.scanMetrics.addToCounter(ScanMetrics.REGIONS_SCANNED_METRIC_NAME, 1);</span>
+<span class="source-line-no">198</span><span id="line-198">        }</span>
+<span class="source-line-no">199</span><span id="line-199">      }</span>
+<span class="source-line-no">200</span><span id="line-200"></span>
+<span class="source-line-no">201</span><span id="line-201">      try {</span>
+<span class="source-line-no">202</span><span id="line-202">        result = currentRegionScanner.next();</span>
+<span class="source-line-no">203</span><span id="line-203">        if (result != null) {</span>
+<span class="source-line-no">204</span><span id="line-204">          if (scan.getLimit() &gt; 0 &amp;&amp; ++this.numOfCompleteRows &gt; scan.getLimit()) {</span>
+<span class="source-line-no">205</span><span id="line-205">            result = null;</span>
+<span class="source-line-no">206</span><span id="line-206">          }</span>
+<span class="source-line-no">207</span><span id="line-207">          return result;</span>
+<span class="source-line-no">208</span><span id="line-208">        }</span>
+<span class="source-line-no">209</span><span id="line-209">      } finally {</span>
+<span class="source-line-no">210</span><span id="line-210">        if (result == null) {</span>
+<span class="source-line-no">211</span><span id="line-211">          currentRegionScanner.close();</span>
+<span class="source-line-no">212</span><span id="line-212">          currentRegionScanner = null;</span>
+<span class="source-line-no">213</span><span id="line-213">        }</span>
+<span class="source-line-no">214</span><span id="line-214">      }</span>
+<span class="source-line-no">215</span><span id="line-215">    }</span>
+<span class="source-line-no">216</span><span id="line-216">  }</span>
+<span class="source-line-no">217</span><span id="line-217"></span>
+<span class="source-line-no">218</span><span id="line-218">  private void cleanup() {</span>
+<span class="source-line-no">219</span><span id="line-219">    try {</span>
+<span class="source-line-no">220</span><span id="line-220">      if (fs.exists(this.restoreDir)) {</span>
+<span class="source-line-no">221</span><span id="line-221">        if (!fs.delete(this.restoreDir, true)) {</span>
+<span class="source-line-no">222</span><span id="line-222">          LOG.warn(</span>
+<span class="source-line-no">223</span><span id="line-223">            "Delete restore directory for the snapshot failed. restoreDir: " + this.restoreDir);</span>
+<span class="source-line-no">224</span><span id="line-224">        }</span>
+<span class="source-line-no">225</span><span id="line-225">      }</span>
+<span class="source-line-no">226</span><span id="line-226">    } catch (IOException ex) {</span>
+<span class="source-line-no">227</span><span id="line-227">      LOG.warn(</span>
+<span class="source-line-no">228</span><span id="line-228">        "Could not delete restore directory for the snapshot. restoreDir: " + this.restoreDir, ex);</span>
+<span class="source-line-no">229</span><span id="line-229">    }</span>
+<span class="source-line-no">230</span><span id="line-230">  }</span>
+<span class="source-line-no">231</span><span id="line-231"></span>
+<span class="source-line-no">232</span><span id="line-232">  @Override</span>
+<span class="source-line-no">233</span><span id="line-233">  public void close() {</span>
+<span class="source-line-no">234</span><span id="line-234">    if (currentRegionScanner != null) {</span>
+<span class="source-line-no">235</span><span id="line-235">      currentRegionScanner.close();</span>
+<span class="source-line-no">236</span><span id="line-236">    }</span>
+<span class="source-line-no">237</span><span id="line-237">    // if snapshotAlreadyRestored is true, then we should invoke cleanup() method by hand.</span>
+<span class="source-line-no">238</span><span id="line-238">    if (!this.snapshotAlreadyRestored) {</span>
+<span class="source-line-no">239</span><span id="line-239">      cleanup();</span>
+<span class="source-line-no">240</span><span id="line-240">    }</span>
+<span class="source-line-no">241</span><span id="line-241">  }</span>
+<span class="source-line-no">242</span><span id="line-242"></span>
+<span class="source-line-no">243</span><span id="line-243">  @Override</span>
+<span class="source-line-no">244</span><span id="line-244">  public boolean renewLease() {</span>
+<span class="source-line-no">245</span><span id="line-245">    throw new UnsupportedOperationException();</span>
+<span class="source-line-no">246</span><span id="line-246">  }</span>
+<span class="source-line-no">247</span><span id="line-247"></span>
+<span class="source-line-no">248</span><span id="line-248">}</span>
 
 
 
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
index 4f25eecac2b..5d87836eb78 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.InputSplit.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
index 988b049b680..c9f4537ca7b 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.RecordReader.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
index ac564cc4ba2..8edc449b184 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/mapreduce/TableSnapshotInputFormatImpl.html
@@ -376,7 +376,7 @@
 <span class="source-line-no">363</span><span id="line-363">        continue;</span>
 <span class="source-line-no">364</span><span id="line-364">      }</span>
 <span class="source-line-no">365</span><span id="line-365">      // The mob region is a dummy region used only to organise mob files under mobdir. It has no</span>
-<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open, and holds no rows. See HBASE-30365.</span>
+<span class="source-line-no">366</span><span id="line-366">      // region directory under the table dir to open. See HBASE-30365.</span>
 <span class="source-line-no">367</span><span id="line-367">      if (MobUtils.isMobRegionInfo(hri)) {</span>
 <span class="source-line-no">368</span><span id="line-368">        continue;</span>
 <span class="source-line-no">369</span><span id="line-369">      }</span>
diff --git a/hbase-website/dependency-convergence.html b/hbase-website/dependency-convergence.html
index 7c1a2ed8fad..aef5a6cff17 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 2026-09-08
+ | 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 2026-09-09
  | 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 153de835ff8..4408ea355d8 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 2026-09-08
+ | 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 2026-09-09
  | 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 388d9bf6f17..6345cff7542 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 2026-09-08
+ | 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 2026-09-09
  | 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 fae1642d781..d43aea07c14 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 2026-09-08
+ | 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 2026-09-09
  | 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 eae07b80e0e..e0f3cab047a 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 2026-09-08
+ | 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 2026-09-09
  | 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 aad8af043bf..9b4d26a30e3 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 2026-09-08
+ | 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 2026-09-09
  | 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 18179843b06..a00b6fb363b 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 2026-09-08
+ | 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 2026-09-09
  | 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 931615ee5a1..935220c04c8 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 2026-09-08
+ | 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 2026-09-09
  | 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 4eebd6f0711..f8f4535a05b 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 2026-09-08
+ | 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 2026-09-09
  | 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 b2d9d728de6..dc03eb5fc60 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 2026-09-08
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 2026-09-09
  | 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 5f454567fe3..dfe19274e02 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 2026-09-08
+ | 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 2026-09-09
  | 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 dc4041e779f..22bc2720a26 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 2026-09-08
+ | 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 2026-09-09
  | 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 9325f507d7c..019a2db735b 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 2026-09-08
+ | 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 2026-09-09
  | 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 2a1d139740d..1264a6ad543 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 2026-09-08
+ | 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 2026-09-09
  | 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 26407271f0d..f622194180e 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 2026-09-08
+ | 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 2026-09-09
  | 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 1d14d77b25a..0b7997eba1d 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 2026-09-08
+ | 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 2026-09-09
  | 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 d7ab5bd536c..287c8fd3a21 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 2026-09-08
+ | 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 2026-09-09
  | 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 7bb6082f09d..7dd9d58d330 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 2026-09-08
+ | 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 2026-09-09
  | 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 603b21b5536..a7ae2bed34b 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 2026-09-08
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-info at 2026-09-09
  | 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 d78478e7937..c3e477132a7 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 2026-09-08
+ | Generated by Apache Maven Doxia Site Renderer 2.0.0 from org.apache.maven.plugins:maven-site-plugin:3.21.0:project-reports at 2026-09-09
  | 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 4d1a1152dff..7130a31550f 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 2026-09-08
+ | 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 2026-09-09
  | 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 737e7fff8b4..1546cb2ed45 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 2026-09-08
+ | 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 2026-09-09
  | 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 f2508911eb5..e1994ce0ecf 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 2026-09-08
+ | 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 2026-09-09
  | Rendered using Apache Maven Fluido Skin 2.0.0-M9
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
diff --git a/testapidocs/index-all.html b/testapidocs/index-all.html
index dc81562c146..c56ab1a16eb 100644
--- a/testapidocs/index-all.html
+++ b/testapidocs/index-all.html
@@ -40200,6 +40200,8 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt><a href="../apidocs/org/apache/hadoop/hbase/client/TestScannersFromClientSide.html#testScannerWithPartialResults()" class="member-name-link external-link" title="class or interface in org.apache.hadoop.hbase.client">testScannerWithPartialResults()</a> - Method in class org.apache.hadoop.hbase.client.<a href="../apidocs/org/apache/hadoop/hbase/client/TestScannersFromClientSide.html" title="class or interface in org.apache.hadoop.hbase.client" class="external-link">TestScannersFromClie [...]
 <dd>&nbsp;</dd>
+<dt><a href="../apidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#testScannerWithRestoredMobSnapshot()" class="member-name-link external-link" title="class or interface in org.apache.hadoop.hbase.client">testScannerWithRestoredMobSnapshot()</a> - Method in class org.apache.hadoop.hbase.client.<a href="../apidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html" title="class or interface in org.apache.hadoop.hbase.client" class="external-link">TestTableSnaps [...]
+<dd>&nbsp;</dd>
 <dt><a href="../apidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#testScannerWithRestoreScanner()" class="member-name-link external-link" title="class or interface in org.apache.hadoop.hbase.client">testScannerWithRestoreScanner()</a> - Method in class org.apache.hadoop.hbase.client.<a href="../apidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html" title="class or interface in org.apache.hadoop.hbase.client" class="external-link">TestTableSnapshotScanner [...]
 <dd>&nbsp;</dd>
 <dt><a href="../apidocs/org/apache/hadoop/hbase/rest/TestTableScan.html#testScanningUnknownColumnJson()" class="member-name-link external-link" title="class or interface in org.apache.hadoop.hbase.rest">testScanningUnknownColumnJson()</a> - Method in class org.apache.hadoop.hbase.rest.<a href="../apidocs/org/apache/hadoop/hbase/rest/TestTableScan.html" title="class or interface in org.apache.hadoop.hbase.rest" class="external-link">TestTableScan</a></dt>
diff --git a/testapidocs/member-search-index.js b/testapidocs/member-search-index.js
index 2ce794dd574..ab7a35a6f12 100644
--- a/testapidocs/member-search-index.js
+++ b/testapidocs/member-search-index.js
@@ -1 +1 @@
-memberSearchIndex = [{"p":"org.apache.hadoop.hbase.backup","c":"TestSystemTableSnapshot","l":"_testBackupRestoreSystemTable()"},{"p":"org.apache.hadoop.hbase.coprocessor","c":"TestRegionObserverInterface","l":"A"},{"p":"org.apache.hadoop.hbase.client","c":"TestGetProcedureResult.DummyProcedure","l":"abort(MasterProcedureEnv)","u":"abort(org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv)"},{"p":"org.apache.hadoop.hbase.master","c":"TestMigrateNamespaceTable.SuspendProcedure","l" [...]
\ No newline at end of file
+memberSearchIndex = [{"p":"org.apache.hadoop.hbase.backup","c":"TestSystemTableSnapshot","l":"_testBackupRestoreSystemTable()"},{"p":"org.apache.hadoop.hbase.coprocessor","c":"TestRegionObserverInterface","l":"A"},{"p":"org.apache.hadoop.hbase.client","c":"TestGetProcedureResult.DummyProcedure","l":"abort(MasterProcedureEnv)","u":"abort(org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv)"},{"p":"org.apache.hadoop.hbase.master","c":"TestMigrateNamespaceTable.SuspendProcedure","l" [...]
\ No newline at end of file
diff --git a/testapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html b/testapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
index 9ffff1f2453..fbcf5419bbf 100644
--- a/testapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
+++ b/testapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
@@ -62,574 +62,600 @@
 <span class="source-line-no">049</span><span id="line-49">import org.apache.hadoop.hbase.regionserver.StoreContext;</span>
 <span class="source-line-no">050</span><span id="line-50">import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker;</span>
 <span class="source-line-no">051</span><span id="line-51">import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;</span>
-<span class="source-line-no">052</span><span id="line-52">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
-<span class="source-line-no">053</span><span id="line-53">import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;</span>
-<span class="source-line-no">054</span><span id="line-54">import org.apache.hadoop.hbase.testclassification.ClientTests;</span>
-<span class="source-line-no">055</span><span id="line-55">import org.apache.hadoop.hbase.testclassification.LargeTests;</span>
-<span class="source-line-no">056</span><span id="line-56">import org.apache.hadoop.hbase.util.Bytes;</span>
-<span class="source-line-no">057</span><span id="line-57">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
-<span class="source-line-no">058</span><span id="line-58">import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;</span>
-<span class="source-line-no">059</span><span id="line-59">import org.apache.hadoop.hbase.util.FSUtils;</span>
-<span class="source-line-no">060</span><span id="line-60">import org.apache.hadoop.hbase.util.HFileArchiveUtil;</span>
-<span class="source-line-no">061</span><span id="line-61">import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;</span>
-<span class="source-line-no">062</span><span id="line-62">import org.junit.jupiter.api.AfterEach;</span>
-<span class="source-line-no">063</span><span id="line-63">import org.junit.jupiter.api.BeforeEach;</span>
-<span class="source-line-no">064</span><span id="line-64">import org.junit.jupiter.api.Tag;</span>
-<span class="source-line-no">065</span><span id="line-65">import org.junit.jupiter.api.Test;</span>
-<span class="source-line-no">066</span><span id="line-66">import org.junit.jupiter.api.TestInfo;</span>
-<span class="source-line-no">067</span><span id="line-67">import org.slf4j.Logger;</span>
-<span class="source-line-no">068</span><span id="line-68">import org.slf4j.LoggerFactory;</span>
-<span class="source-line-no">069</span><span id="line-69"></span>
-<span class="source-line-no">070</span><span id="line-70">@Tag(LargeTests.TAG)</span>
-<span class="source-line-no">071</span><span id="line-71">@Tag(ClientTests.TAG)</span>
-<span class="source-line-no">072</span><span id="line-72">public class TestTableSnapshotScanner {</span>
-<span class="source-line-no">073</span><span id="line-73"></span>
-<span class="source-line-no">074</span><span id="line-74">  private static final Logger LOG = LoggerFactory.getLogger(TestTableSnapshotScanner.class);</span>
-<span class="source-line-no">075</span><span id="line-75">  private final HBaseTestingUtil UTIL = new HBaseTestingUtil();</span>
-<span class="source-line-no">076</span><span id="line-76">  private static final int NUM_REGION_SERVERS = 2;</span>
-<span class="source-line-no">077</span><span id="line-77">  private static final byte[][] FAMILIES = { Bytes.toBytes("f1"), Bytes.toBytes("f2") };</span>
-<span class="source-line-no">078</span><span id="line-78">  public static byte[] bbb = Bytes.toBytes("bbb");</span>
-<span class="source-line-no">079</span><span id="line-79">  public static byte[] yyy = Bytes.toBytes("yyy");</span>
-<span class="source-line-no">080</span><span id="line-80"></span>
-<span class="source-line-no">081</span><span id="line-81">  private FileSystem fs;</span>
-<span class="source-line-no">082</span><span id="line-82">  private Path rootDir;</span>
-<span class="source-line-no">083</span><span id="line-83">  private boolean clusterUp;</span>
-<span class="source-line-no">084</span><span id="line-84"></span>
-<span class="source-line-no">085</span><span id="line-85">  private String methodName;</span>
-<span class="source-line-no">086</span><span id="line-86"></span>
-<span class="source-line-no">087</span><span id="line-87">  public static void blockUntilSplitFinished(HBaseTestingUtil util, TableName tableName,</span>
-<span class="source-line-no">088</span><span id="line-88">    int expectedRegionSize) throws Exception {</span>
-<span class="source-line-no">089</span><span id="line-89">    for (int i = 0; i &lt; 100; i++) {</span>
-<span class="source-line-no">090</span><span id="line-90">      List&lt;RegionInfo&gt; hRegionInfoList = util.getAdmin().getRegions(tableName);</span>
-<span class="source-line-no">091</span><span id="line-91">      if (hRegionInfoList.size() &gt;= expectedRegionSize) {</span>
-<span class="source-line-no">092</span><span id="line-92">        break;</span>
-<span class="source-line-no">093</span><span id="line-93">      }</span>
-<span class="source-line-no">094</span><span id="line-94">      Thread.sleep(1000);</span>
-<span class="source-line-no">095</span><span id="line-95">    }</span>
-<span class="source-line-no">096</span><span id="line-96">  }</span>
-<span class="source-line-no">097</span><span id="line-97"></span>
-<span class="source-line-no">098</span><span id="line-98">  @BeforeEach</span>
-<span class="source-line-no">099</span><span id="line-99">  public void setupCluster(TestInfo testInfo) throws Exception {</span>
-<span class="source-line-no">100</span><span id="line-100">    methodName = testInfo.getTestMethod().get().getName();</span>
-<span class="source-line-no">101</span><span id="line-101">    setupConf(UTIL.getConfiguration());</span>
-<span class="source-line-no">102</span><span id="line-102">    StartTestingClusterOption option =</span>
-<span class="source-line-no">103</span><span id="line-103">      StartTestingClusterOption.builder().numRegionServers(NUM_REGION_SERVERS)</span>
-<span class="source-line-no">104</span><span id="line-104">        .numDataNodes(NUM_REGION_SERVERS).createRootDir(true).build();</span>
-<span class="source-line-no">105</span><span id="line-105">    UTIL.startMiniCluster(option);</span>
-<span class="source-line-no">106</span><span id="line-106">    clusterUp = true;</span>
-<span class="source-line-no">107</span><span id="line-107">    rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
-<span class="source-line-no">108</span><span id="line-108">    fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
-<span class="source-line-no">109</span><span id="line-109">  }</span>
-<span class="source-line-no">110</span><span id="line-110"></span>
-<span class="source-line-no">111</span><span id="line-111">  @AfterEach</span>
-<span class="source-line-no">112</span><span id="line-112">  public void tearDownCluster() throws Exception {</span>
-<span class="source-line-no">113</span><span id="line-113">    if (clusterUp) {</span>
-<span class="source-line-no">114</span><span id="line-114">      UTIL.shutdownMiniCluster();</span>
-<span class="source-line-no">115</span><span id="line-115">    }</span>
-<span class="source-line-no">116</span><span id="line-116">  }</span>
-<span class="source-line-no">117</span><span id="line-117"></span>
-<span class="source-line-no">118</span><span id="line-118">  protected void setupConf(Configuration conf) {</span>
-<span class="source-line-no">119</span><span id="line-119">    // Enable snapshot</span>
-<span class="source-line-no">120</span><span id="line-120">    conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);</span>
-<span class="source-line-no">121</span><span id="line-121">  }</span>
-<span class="source-line-no">122</span><span id="line-122"></span>
-<span class="source-line-no">123</span><span id="line-123">  public static void createTableAndSnapshot(HBaseTestingUtil util, TableName tableName,</span>
-<span class="source-line-no">124</span><span id="line-124">    String snapshotName, int numRegions) throws Exception {</span>
-<span class="source-line-no">125</span><span id="line-125">    try {</span>
-<span class="source-line-no">126</span><span id="line-126">      util.deleteTable(tableName);</span>
-<span class="source-line-no">127</span><span id="line-127">    } catch (Exception ex) {</span>
-<span class="source-line-no">128</span><span id="line-128">      // ignore</span>
-<span class="source-line-no">129</span><span id="line-129">    }</span>
-<span class="source-line-no">130</span><span id="line-130"></span>
-<span class="source-line-no">131</span><span id="line-131">    if (numRegions &gt; 1) {</span>
-<span class="source-line-no">132</span><span id="line-132">      util.createTable(tableName, FAMILIES, 1, bbb, yyy, numRegions);</span>
-<span class="source-line-no">133</span><span id="line-133">    } else {</span>
-<span class="source-line-no">134</span><span id="line-134">      util.createTable(tableName, FAMILIES);</span>
-<span class="source-line-no">135</span><span id="line-135">    }</span>
-<span class="source-line-no">136</span><span id="line-136">    Admin admin = util.getAdmin();</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">    // put some stuff in the table</span>
-<span class="source-line-no">139</span><span id="line-139">    Table table = util.getConnection().getTable(tableName);</span>
-<span class="source-line-no">140</span><span id="line-140">    util.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">141</span><span id="line-141"></span>
-<span class="source-line-no">142</span><span id="line-142">    Path rootDir = CommonFSUtils.getRootDir(util.getConfiguration());</span>
-<span class="source-line-no">143</span><span id="line-143">    FileSystem fs = rootDir.getFileSystem(util.getConfiguration());</span>
-<span class="source-line-no">144</span><span id="line-144"></span>
-<span class="source-line-no">145</span><span id="line-145">    SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES), null,</span>
-<span class="source-line-no">146</span><span id="line-146">      snapshotName, rootDir, fs, true);</span>
-<span class="source-line-no">147</span><span id="line-147"></span>
-<span class="source-line-no">148</span><span id="line-148">    // load different values</span>
-<span class="source-line-no">149</span><span id="line-149">    byte[] value = Bytes.toBytes("after_snapshot_value");</span>
-<span class="source-line-no">150</span><span id="line-150">    util.loadTable(table, FAMILIES, value);</span>
-<span class="source-line-no">151</span><span id="line-151"></span>
-<span class="source-line-no">152</span><span id="line-152">    // cause flush to create new files in the region</span>
-<span class="source-line-no">153</span><span id="line-153">    admin.flush(tableName);</span>
-<span class="source-line-no">154</span><span id="line-154">    table.close();</span>
-<span class="source-line-no">155</span><span id="line-155">  }</span>
-<span class="source-line-no">156</span><span id="line-156"></span>
-<span class="source-line-no">157</span><span id="line-157">  @Test</span>
-<span class="source-line-no">158</span><span id="line-158">  public void testNoDuplicateResultsWhenSplitting() throws Exception {</span>
-<span class="source-line-no">159</span><span id="line-159">    TableName tableName = TableName.valueOf("testNoDuplicateResultsWhenSplitting");</span>
-<span class="source-line-no">160</span><span id="line-160">    String snapshotName = "testSnapshotBug";</span>
-<span class="source-line-no">161</span><span id="line-161">    try {</span>
-<span class="source-line-no">162</span><span id="line-162">      if (UTIL.getAdmin().tableExists(tableName)) {</span>
-<span class="source-line-no">163</span><span id="line-163">        UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">164</span><span id="line-164">      }</span>
-<span class="source-line-no">165</span><span id="line-165"></span>
-<span class="source-line-no">166</span><span id="line-166">      UTIL.createTable(tableName, FAMILIES);</span>
-<span class="source-line-no">167</span><span id="line-167">      Admin admin = UTIL.getAdmin();</span>
-<span class="source-line-no">168</span><span id="line-168"></span>
-<span class="source-line-no">169</span><span id="line-169">      // put some stuff in the table</span>
-<span class="source-line-no">170</span><span id="line-170">      Table table = UTIL.getConnection().getTable(tableName);</span>
-<span class="source-line-no">171</span><span id="line-171">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">172</span><span id="line-172"></span>
-<span class="source-line-no">173</span><span id="line-173">      // split to 2 regions</span>
-<span class="source-line-no">174</span><span id="line-174">      admin.split(tableName, Bytes.toBytes("eee"));</span>
-<span class="source-line-no">175</span><span id="line-175">      blockUntilSplitFinished(UTIL, tableName, 2);</span>
-<span class="source-line-no">176</span><span id="line-176"></span>
-<span class="source-line-no">177</span><span id="line-177">      Path rootDir = CommonFSUtils.getRootDir(UTIL.getConfiguration());</span>
-<span class="source-line-no">178</span><span id="line-178">      FileSystem fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
-<span class="source-line-no">179</span><span id="line-179"></span>
-<span class="source-line-no">180</span><span id="line-180">      SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES),</span>
-<span class="source-line-no">181</span><span id="line-181">        null, snapshotName, rootDir, fs, true);</span>
-<span class="source-line-no">182</span><span id="line-182"></span>
-<span class="source-line-no">183</span><span id="line-183">      // load different values</span>
-<span class="source-line-no">184</span><span id="line-184">      byte[] value = Bytes.toBytes("after_snapshot_value");</span>
-<span class="source-line-no">185</span><span id="line-185">      UTIL.loadTable(table, FAMILIES, value);</span>
-<span class="source-line-no">186</span><span id="line-186"></span>
-<span class="source-line-no">187</span><span id="line-187">      // cause flush to create new files in the region</span>
-<span class="source-line-no">188</span><span id="line-188">      admin.flush(tableName);</span>
-<span class="source-line-no">189</span><span id="line-189">      table.close();</span>
-<span class="source-line-no">190</span><span id="line-190"></span>
-<span class="source-line-no">191</span><span id="line-191">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">192</span><span id="line-192">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">193</span><span id="line-193"></span>
-<span class="source-line-no">194</span><span id="line-194">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">195</span><span id="line-195">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">196</span><span id="line-196"></span>
-<span class="source-line-no">197</span><span id="line-197">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">198</span><span id="line-198">      scanner.close();</span>
-<span class="source-line-no">199</span><span id="line-199">    } catch (Exception e) {</span>
-<span class="source-line-no">200</span><span id="line-200">      e.printStackTrace();</span>
-<span class="source-line-no">201</span><span id="line-201">    } finally {</span>
-<span class="source-line-no">202</span><span id="line-202">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">203</span><span id="line-203">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">204</span><span id="line-204">    }</span>
-<span class="source-line-no">205</span><span id="line-205">  }</span>
-<span class="source-line-no">206</span><span id="line-206"></span>
-<span class="source-line-no">207</span><span id="line-207">  @Test</span>
-<span class="source-line-no">208</span><span id="line-208">  public void testScanLimit() throws Exception {</span>
-<span class="source-line-no">209</span><span id="line-209">    final TableName tableName = TableName.valueOf(methodName);</span>
-<span class="source-line-no">210</span><span id="line-210">    final String snapshotName = tableName + "Snapshot";</span>
-<span class="source-line-no">211</span><span id="line-211">    TableSnapshotScanner scanner = null;</span>
-<span class="source-line-no">212</span><span id="line-212">    try {</span>
-<span class="source-line-no">213</span><span id="line-213">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">214</span><span id="line-214">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">215</span><span id="line-215">      Scan scan = new Scan().withStartRow(bbb).setLimit(100); // limit the scan</span>
-<span class="source-line-no">216</span><span id="line-216"></span>
-<span class="source-line-no">217</span><span id="line-217">      scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">218</span><span id="line-218">      int count = 0;</span>
-<span class="source-line-no">219</span><span id="line-219">      while (true) {</span>
-<span class="source-line-no">220</span><span id="line-220">        Result result = scanner.next();</span>
-<span class="source-line-no">221</span><span id="line-221">        if (result == null) {</span>
-<span class="source-line-no">222</span><span id="line-222">          break;</span>
-<span class="source-line-no">223</span><span id="line-223">        }</span>
-<span class="source-line-no">224</span><span id="line-224">        count++;</span>
-<span class="source-line-no">225</span><span id="line-225">      }</span>
-<span class="source-line-no">226</span><span id="line-226">      assertEquals(100, count);</span>
-<span class="source-line-no">227</span><span id="line-227">    } finally {</span>
-<span class="source-line-no">228</span><span id="line-228">      if (scanner != null) {</span>
-<span class="source-line-no">229</span><span id="line-229">        scanner.close();</span>
-<span class="source-line-no">230</span><span id="line-230">      }</span>
-<span class="source-line-no">231</span><span id="line-231">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">232</span><span id="line-232">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">233</span><span id="line-233">    }</span>
-<span class="source-line-no">234</span><span id="line-234">  }</span>
-<span class="source-line-no">235</span><span id="line-235"></span>
-<span class="source-line-no">236</span><span id="line-236">  @Test</span>
-<span class="source-line-no">237</span><span id="line-237">  public void testWithSingleRegion() throws Exception {</span>
-<span class="source-line-no">238</span><span id="line-238">    testScanner(UTIL, "testWithSingleRegion", 1, false);</span>
-<span class="source-line-no">239</span><span id="line-239">  }</span>
-<span class="source-line-no">240</span><span id="line-240"></span>
-<span class="source-line-no">241</span><span id="line-241">  @Test</span>
-<span class="source-line-no">242</span><span id="line-242">  public void testWithMultiRegion() throws Exception {</span>
-<span class="source-line-no">243</span><span id="line-243">    testScanner(UTIL, "testWithMultiRegion", 10, false);</span>
-<span class="source-line-no">244</span><span id="line-244">  }</span>
-<span class="source-line-no">245</span><span id="line-245"></span>
-<span class="source-line-no">246</span><span id="line-246">  @Test</span>
-<span class="source-line-no">247</span><span id="line-247">  public void testWithOfflineHBaseMultiRegion() throws Exception {</span>
-<span class="source-line-no">248</span><span id="line-248">    testScanner(UTIL, "testWithMultiRegion", 20, true);</span>
-<span class="source-line-no">249</span><span id="line-249">  }</span>
-<span class="source-line-no">250</span><span id="line-250"></span>
-<span class="source-line-no">251</span><span id="line-251">  private ScanMetrics createTableSnapshotScannerAndGetScanMetrics(boolean enableScanMetrics,</span>
-<span class="source-line-no">252</span><span id="line-252">    boolean enableScanMetricsByRegion, byte[] endKey) throws Exception {</span>
-<span class="source-line-no">253</span><span id="line-253">    TableName tableName = TableName.valueOf(methodName + "_TABLE");</span>
-<span class="source-line-no">254</span><span id="line-254">    String snapshotName = methodName + "_SNAPSHOT";</span>
-<span class="source-line-no">255</span><span id="line-255">    try {</span>
-<span class="source-line-no">256</span><span id="line-256">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">257</span><span id="line-257">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">258</span><span id="line-258">      Scan scan = new Scan().withStartRow(bbb).withStopRow(endKey);</span>
-<span class="source-line-no">259</span><span id="line-259">      scan.setScanMetricsEnabled(enableScanMetrics);</span>
-<span class="source-line-no">260</span><span id="line-260">      scan.setEnableScanMetricsByRegion(enableScanMetricsByRegion);</span>
-<span class="source-line-no">261</span><span id="line-261">      Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">262</span><span id="line-262"></span>
-<span class="source-line-no">263</span><span id="line-263">      TableSnapshotScanner snapshotScanner =</span>
-<span class="source-line-no">264</span><span id="line-264">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">265</span><span id="line-265">      verifyScanner(snapshotScanner, bbb, endKey);</span>
-<span class="source-line-no">266</span><span id="line-266">      return snapshotScanner.getScanMetrics();</span>
-<span class="source-line-no">267</span><span id="line-267">    } finally {</span>
-<span class="source-line-no">268</span><span id="line-268">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">269</span><span id="line-269">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">270</span><span id="line-270">    }</span>
-<span class="source-line-no">271</span><span id="line-271">  }</span>
-<span class="source-line-no">272</span><span id="line-272"></span>
-<span class="source-line-no">273</span><span id="line-273">  @Test</span>
-<span class="source-line-no">274</span><span id="line-274">  public void testScanMetricsDisabled() throws Exception {</span>
-<span class="source-line-no">275</span><span id="line-275">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(false, false, yyy);</span>
-<span class="source-line-no">276</span><span id="line-276">    assertNull(scanMetrics);</span>
-<span class="source-line-no">277</span><span id="line-277">  }</span>
-<span class="source-line-no">278</span><span id="line-278"></span>
-<span class="source-line-no">279</span><span id="line-279">  @Test</span>
-<span class="source-line-no">280</span><span id="line-280">  public void testScanMetricsWithScanMetricsByRegionDisabled() throws Exception {</span>
-<span class="source-line-no">281</span><span id="line-281">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, false, yyy);</span>
-<span class="source-line-no">282</span><span id="line-282">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">283</span><span id="line-283">    int rowsScanned = 0;</span>
-<span class="source-line-no">284</span><span id="line-284">    for (byte[] row : HBaseTestingUtil.ROWS) {</span>
-<span class="source-line-no">285</span><span id="line-285">      if (Bytes.compareTo(row, bbb) &gt;= 0 &amp;&amp; Bytes.compareTo(row, yyy) &lt; 0) {</span>
-<span class="source-line-no">286</span><span id="line-286">        rowsScanned++;</span>
-<span class="source-line-no">287</span><span id="line-287">      }</span>
-<span class="source-line-no">288</span><span id="line-288">    }</span>
-<span class="source-line-no">289</span><span id="line-289">    Map&lt;String, Long&gt; metricsMap = scanMetrics.getMetricsMap();</span>
-<span class="source-line-no">290</span><span id="line-290">    assertEquals(rowsScanned, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
-<span class="source-line-no">291</span><span id="line-291">  }</span>
-<span class="source-line-no">292</span><span id="line-292"></span>
-<span class="source-line-no">293</span><span id="line-293">  @Test</span>
-<span class="source-line-no">294</span><span id="line-294">  public void testScanMetricsByRegionForSingleRegion() throws Exception {</span>
-<span class="source-line-no">295</span><span id="line-295">    // Scan single row with row key bbb</span>
-<span class="source-line-no">296</span><span id="line-296">    byte[] bbc = Bytes.toBytes("bbc");</span>
-<span class="source-line-no">297</span><span id="line-297">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, bbc);</span>
-<span class="source-line-no">298</span><span id="line-298">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">299</span><span id="line-299">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
-<span class="source-line-no">300</span><span id="line-300">      scanMetrics.collectMetricsByRegion();</span>
-<span class="source-line-no">301</span><span id="line-301">    assertEquals(1, scanMetricsByRegion.size());</span>
-<span class="source-line-no">302</span><span id="line-302">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
-<span class="source-line-no">303</span><span id="line-303">      .entrySet()) {</span>
-<span class="source-line-no">304</span><span id="line-304">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
-<span class="source-line-no">305</span><span id="line-305">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
-<span class="source-line-no">306</span><span id="line-306">      assertNull(scanMetricsRegionInfo.getServerName());</span>
-<span class="source-line-no">307</span><span id="line-307">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
-<span class="source-line-no">308</span><span id="line-308">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
-<span class="source-line-no">309</span><span id="line-309">      assertEquals(1, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
-<span class="source-line-no">310</span><span id="line-310">    }</span>
-<span class="source-line-no">311</span><span id="line-311">  }</span>
-<span class="source-line-no">312</span><span id="line-312"></span>
-<span class="source-line-no">313</span><span id="line-313">  @Test</span>
-<span class="source-line-no">314</span><span id="line-314">  public void testScanMetricsByRegionForMultiRegion() throws Exception {</span>
-<span class="source-line-no">315</span><span id="line-315">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, yyy);</span>
-<span class="source-line-no">316</span><span id="line-316">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">317</span><span id="line-317">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
-<span class="source-line-no">318</span><span id="line-318">      scanMetrics.collectMetricsByRegion();</span>
-<span class="source-line-no">319</span><span id="line-319">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
-<span class="source-line-no">320</span><span id="line-320">      .entrySet()) {</span>
-<span class="source-line-no">321</span><span id="line-321">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
-<span class="source-line-no">322</span><span id="line-322">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
-<span class="source-line-no">323</span><span id="line-323">      assertNull(scanMetricsRegionInfo.getServerName());</span>
-<span class="source-line-no">324</span><span id="line-324">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
-<span class="source-line-no">325</span><span id="line-325">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
-<span class="source-line-no">326</span><span id="line-326">    }</span>
-<span class="source-line-no">327</span><span id="line-327">  }</span>
-<span class="source-line-no">328</span><span id="line-328"></span>
-<span class="source-line-no">329</span><span id="line-329">  @Test</span>
-<span class="source-line-no">330</span><span id="line-330">  public void testScannerWithRestoreScanner() throws Exception {</span>
-<span class="source-line-no">331</span><span id="line-331">    TableName tableName = TableName.valueOf("testScanner");</span>
-<span class="source-line-no">332</span><span id="line-332">    String snapshotName = "testScannerWithRestoreScanner";</span>
-<span class="source-line-no">333</span><span id="line-333">    try {</span>
-<span class="source-line-no">334</span><span id="line-334">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">335</span><span id="line-335">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">336</span><span id="line-336">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">337</span><span id="line-337"></span>
-<span class="source-line-no">338</span><span id="line-338">      Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">339</span><span id="line-339">      Path rootDir = CommonFSUtils.getRootDir(conf);</span>
-<span class="source-line-no">340</span><span id="line-340"></span>
-<span class="source-line-no">341</span><span id="line-341">      TableSnapshotScanner scanner0 =</span>
-<span class="source-line-no">342</span><span id="line-342">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">343</span><span id="line-343">      verifyScanner(scanner0, bbb, yyy);</span>
-<span class="source-line-no">344</span><span id="line-344">      scanner0.close();</span>
-<span class="source-line-no">345</span><span id="line-345"></span>
-<span class="source-line-no">346</span><span id="line-346">      // restore snapshot.</span>
-<span class="source-line-no">347</span><span id="line-347">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">348</span><span id="line-348"></span>
-<span class="source-line-no">349</span><span id="line-349">      // scan the snapshot without restoring snapshot</span>
-<span class="source-line-no">350</span><span id="line-350">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">351</span><span id="line-351">        new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">352</span><span id="line-352">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">353</span><span id="line-353">      scanner.close();</span>
-<span class="source-line-no">354</span><span id="line-354"></span>
-<span class="source-line-no">355</span><span id="line-355">      // check whether the snapshot has been deleted by the close of scanner.</span>
-<span class="source-line-no">356</span><span id="line-356">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">357</span><span id="line-357">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">358</span><span id="line-358">      scanner.close();</span>
-<span class="source-line-no">359</span><span id="line-359"></span>
-<span class="source-line-no">360</span><span id="line-360">      // restore snapshot again.</span>
-<span class="source-line-no">361</span><span id="line-361">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">362</span><span id="line-362"></span>
-<span class="source-line-no">363</span><span id="line-363">      // check whether the snapshot has been deleted by the close of scanner.</span>
-<span class="source-line-no">364</span><span id="line-364">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">365</span><span id="line-365">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">366</span><span id="line-366">      scanner.close();</span>
-<span class="source-line-no">367</span><span id="line-367">    } finally {</span>
-<span class="source-line-no">368</span><span id="line-368">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">369</span><span id="line-369">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">370</span><span id="line-370">    }</span>
-<span class="source-line-no">371</span><span id="line-371">  }</span>
-<span class="source-line-no">372</span><span id="line-372"></span>
-<span class="source-line-no">373</span><span id="line-373">  private void testScanner(HBaseTestingUtil util, String snapshotName, int numRegions,</span>
-<span class="source-line-no">374</span><span id="line-374">    boolean shutdownCluster) throws Exception {</span>
-<span class="source-line-no">375</span><span id="line-375">    TableName tableName = TableName.valueOf("testScanner");</span>
-<span class="source-line-no">376</span><span id="line-376">    try {</span>
-<span class="source-line-no">377</span><span id="line-377">      createTableAndSnapshot(util, tableName, snapshotName, numRegions);</span>
-<span class="source-line-no">378</span><span id="line-378"></span>
-<span class="source-line-no">379</span><span id="line-379">      if (shutdownCluster) {</span>
-<span class="source-line-no">380</span><span id="line-380">        util.shutdownMiniHBaseCluster();</span>
-<span class="source-line-no">381</span><span id="line-381">        clusterUp = false;</span>
-<span class="source-line-no">382</span><span id="line-382">      }</span>
-<span class="source-line-no">383</span><span id="line-383"></span>
-<span class="source-line-no">384</span><span id="line-384">      Path restoreDir = util.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">385</span><span id="line-385">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">386</span><span id="line-386"></span>
-<span class="source-line-no">387</span><span id="line-387">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">388</span><span id="line-388">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">389</span><span id="line-389"></span>
-<span class="source-line-no">390</span><span id="line-390">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">391</span><span id="line-391">      scanner.close();</span>
+<span class="source-line-no">052</span><span id="line-52">import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils;</span>
+<span class="source-line-no">053</span><span id="line-53">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
+<span class="source-line-no">054</span><span id="line-54">import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;</span>
+<span class="source-line-no">055</span><span id="line-55">import org.apache.hadoop.hbase.testclassification.ClientTests;</span>
+<span class="source-line-no">056</span><span id="line-56">import org.apache.hadoop.hbase.testclassification.LargeTests;</span>
+<span class="source-line-no">057</span><span id="line-57">import org.apache.hadoop.hbase.util.Bytes;</span>
+<span class="source-line-no">058</span><span id="line-58">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
+<span class="source-line-no">059</span><span id="line-59">import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;</span>
+<span class="source-line-no">060</span><span id="line-60">import org.apache.hadoop.hbase.util.FSUtils;</span>
+<span class="source-line-no">061</span><span id="line-61">import org.apache.hadoop.hbase.util.HFileArchiveUtil;</span>
+<span class="source-line-no">062</span><span id="line-62">import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;</span>
+<span class="source-line-no">063</span><span id="line-63">import org.junit.jupiter.api.AfterEach;</span>
+<span class="source-line-no">064</span><span id="line-64">import org.junit.jupiter.api.BeforeEach;</span>
+<span class="source-line-no">065</span><span id="line-65">import org.junit.jupiter.api.Tag;</span>
+<span class="source-line-no">066</span><span id="line-66">import org.junit.jupiter.api.Test;</span>
+<span class="source-line-no">067</span><span id="line-67">import org.junit.jupiter.api.TestInfo;</span>
+<span class="source-line-no">068</span><span id="line-68">import org.slf4j.Logger;</span>
+<span class="source-line-no">069</span><span id="line-69">import org.slf4j.LoggerFactory;</span>
+<span class="source-line-no">070</span><span id="line-70"></span>
+<span class="source-line-no">071</span><span id="line-71">@Tag(LargeTests.TAG)</span>
+<span class="source-line-no">072</span><span id="line-72">@Tag(ClientTests.TAG)</span>
+<span class="source-line-no">073</span><span id="line-73">public class TestTableSnapshotScanner {</span>
+<span class="source-line-no">074</span><span id="line-74"></span>
+<span class="source-line-no">075</span><span id="line-75">  private static final Logger LOG = LoggerFactory.getLogger(TestTableSnapshotScanner.class);</span>
+<span class="source-line-no">076</span><span id="line-76">  private final HBaseTestingUtil UTIL = new HBaseTestingUtil();</span>
+<span class="source-line-no">077</span><span id="line-77">  private static final int NUM_REGION_SERVERS = 2;</span>
+<span class="source-line-no">078</span><span id="line-78">  private static final byte[][] FAMILIES = { Bytes.toBytes("f1"), Bytes.toBytes("f2") };</span>
+<span class="source-line-no">079</span><span id="line-79">  public static byte[] bbb = Bytes.toBytes("bbb");</span>
+<span class="source-line-no">080</span><span id="line-80">  public static byte[] yyy = Bytes.toBytes("yyy");</span>
+<span class="source-line-no">081</span><span id="line-81"></span>
+<span class="source-line-no">082</span><span id="line-82">  private FileSystem fs;</span>
+<span class="source-line-no">083</span><span id="line-83">  private Path rootDir;</span>
+<span class="source-line-no">084</span><span id="line-84">  private boolean clusterUp;</span>
+<span class="source-line-no">085</span><span id="line-85"></span>
+<span class="source-line-no">086</span><span id="line-86">  private String methodName;</span>
+<span class="source-line-no">087</span><span id="line-87"></span>
+<span class="source-line-no">088</span><span id="line-88">  public static void blockUntilSplitFinished(HBaseTestingUtil util, TableName tableName,</span>
+<span class="source-line-no">089</span><span id="line-89">    int expectedRegionSize) throws Exception {</span>
+<span class="source-line-no">090</span><span id="line-90">    for (int i = 0; i &lt; 100; i++) {</span>
+<span class="source-line-no">091</span><span id="line-91">      List&lt;RegionInfo&gt; hRegionInfoList = util.getAdmin().getRegions(tableName);</span>
+<span class="source-line-no">092</span><span id="line-92">      if (hRegionInfoList.size() &gt;= expectedRegionSize) {</span>
+<span class="source-line-no">093</span><span id="line-93">        break;</span>
+<span class="source-line-no">094</span><span id="line-94">      }</span>
+<span class="source-line-no">095</span><span id="line-95">      Thread.sleep(1000);</span>
+<span class="source-line-no">096</span><span id="line-96">    }</span>
+<span class="source-line-no">097</span><span id="line-97">  }</span>
+<span class="source-line-no">098</span><span id="line-98"></span>
+<span class="source-line-no">099</span><span id="line-99">  @BeforeEach</span>
+<span class="source-line-no">100</span><span id="line-100">  public void setupCluster(TestInfo testInfo) throws Exception {</span>
+<span class="source-line-no">101</span><span id="line-101">    methodName = testInfo.getTestMethod().get().getName();</span>
+<span class="source-line-no">102</span><span id="line-102">    setupConf(UTIL.getConfiguration());</span>
+<span class="source-line-no">103</span><span id="line-103">    StartTestingClusterOption option =</span>
+<span class="source-line-no">104</span><span id="line-104">      StartTestingClusterOption.builder().numRegionServers(NUM_REGION_SERVERS)</span>
+<span class="source-line-no">105</span><span id="line-105">        .numDataNodes(NUM_REGION_SERVERS).createRootDir(true).build();</span>
+<span class="source-line-no">106</span><span id="line-106">    UTIL.startMiniCluster(option);</span>
+<span class="source-line-no">107</span><span id="line-107">    clusterUp = true;</span>
+<span class="source-line-no">108</span><span id="line-108">    rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
+<span class="source-line-no">109</span><span id="line-109">    fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
+<span class="source-line-no">110</span><span id="line-110">  }</span>
+<span class="source-line-no">111</span><span id="line-111"></span>
+<span class="source-line-no">112</span><span id="line-112">  @AfterEach</span>
+<span class="source-line-no">113</span><span id="line-113">  public void tearDownCluster() throws Exception {</span>
+<span class="source-line-no">114</span><span id="line-114">    if (clusterUp) {</span>
+<span class="source-line-no">115</span><span id="line-115">      UTIL.shutdownMiniCluster();</span>
+<span class="source-line-no">116</span><span id="line-116">    }</span>
+<span class="source-line-no">117</span><span id="line-117">  }</span>
+<span class="source-line-no">118</span><span id="line-118"></span>
+<span class="source-line-no">119</span><span id="line-119">  protected void setupConf(Configuration conf) {</span>
+<span class="source-line-no">120</span><span id="line-120">    // Enable snapshot</span>
+<span class="source-line-no">121</span><span id="line-121">    conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);</span>
+<span class="source-line-no">122</span><span id="line-122">  }</span>
+<span class="source-line-no">123</span><span id="line-123"></span>
+<span class="source-line-no">124</span><span id="line-124">  public static void createTableAndSnapshot(HBaseTestingUtil util, TableName tableName,</span>
+<span class="source-line-no">125</span><span id="line-125">    String snapshotName, int numRegions) throws Exception {</span>
+<span class="source-line-no">126</span><span id="line-126">    try {</span>
+<span class="source-line-no">127</span><span id="line-127">      util.deleteTable(tableName);</span>
+<span class="source-line-no">128</span><span id="line-128">    } catch (Exception ex) {</span>
+<span class="source-line-no">129</span><span id="line-129">      // ignore</span>
+<span class="source-line-no">130</span><span id="line-130">    }</span>
+<span class="source-line-no">131</span><span id="line-131"></span>
+<span class="source-line-no">132</span><span id="line-132">    if (numRegions &gt; 1) {</span>
+<span class="source-line-no">133</span><span id="line-133">      util.createTable(tableName, FAMILIES, 1, bbb, yyy, numRegions);</span>
+<span class="source-line-no">134</span><span id="line-134">    } else {</span>
+<span class="source-line-no">135</span><span id="line-135">      util.createTable(tableName, FAMILIES);</span>
+<span class="source-line-no">136</span><span id="line-136">    }</span>
+<span class="source-line-no">137</span><span id="line-137">    Admin admin = util.getAdmin();</span>
+<span class="source-line-no">138</span><span id="line-138"></span>
+<span class="source-line-no">139</span><span id="line-139">    // put some stuff in the table</span>
+<span class="source-line-no">140</span><span id="line-140">    Table table = util.getConnection().getTable(tableName);</span>
+<span class="source-line-no">141</span><span id="line-141">    util.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">142</span><span id="line-142"></span>
+<span class="source-line-no">143</span><span id="line-143">    Path rootDir = CommonFSUtils.getRootDir(util.getConfiguration());</span>
+<span class="source-line-no">144</span><span id="line-144">    FileSystem fs = rootDir.getFileSystem(util.getConfiguration());</span>
+<span class="source-line-no">145</span><span id="line-145"></span>
+<span class="source-line-no">146</span><span id="line-146">    SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES), null,</span>
+<span class="source-line-no">147</span><span id="line-147">      snapshotName, rootDir, fs, true);</span>
+<span class="source-line-no">148</span><span id="line-148"></span>
+<span class="source-line-no">149</span><span id="line-149">    // load different values</span>
+<span class="source-line-no">150</span><span id="line-150">    byte[] value = Bytes.toBytes("after_snapshot_value");</span>
+<span class="source-line-no">151</span><span id="line-151">    util.loadTable(table, FAMILIES, value);</span>
+<span class="source-line-no">152</span><span id="line-152"></span>
+<span class="source-line-no">153</span><span id="line-153">    // cause flush to create new files in the region</span>
+<span class="source-line-no">154</span><span id="line-154">    admin.flush(tableName);</span>
+<span class="source-line-no">155</span><span id="line-155">    table.close();</span>
+<span class="source-line-no">156</span><span id="line-156">  }</span>
+<span class="source-line-no">157</span><span id="line-157"></span>
+<span class="source-line-no">158</span><span id="line-158">  @Test</span>
+<span class="source-line-no">159</span><span id="line-159">  public void testNoDuplicateResultsWhenSplitting() throws Exception {</span>
+<span class="source-line-no">160</span><span id="line-160">    TableName tableName = TableName.valueOf("testNoDuplicateResultsWhenSplitting");</span>
+<span class="source-line-no">161</span><span id="line-161">    String snapshotName = "testSnapshotBug";</span>
+<span class="source-line-no">162</span><span id="line-162">    try {</span>
+<span class="source-line-no">163</span><span id="line-163">      if (UTIL.getAdmin().tableExists(tableName)) {</span>
+<span class="source-line-no">164</span><span id="line-164">        UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">165</span><span id="line-165">      }</span>
+<span class="source-line-no">166</span><span id="line-166"></span>
+<span class="source-line-no">167</span><span id="line-167">      UTIL.createTable(tableName, FAMILIES);</span>
+<span class="source-line-no">168</span><span id="line-168">      Admin admin = UTIL.getAdmin();</span>
+<span class="source-line-no">169</span><span id="line-169"></span>
+<span class="source-line-no">170</span><span id="line-170">      // put some stuff in the table</span>
+<span class="source-line-no">171</span><span id="line-171">      Table table = UTIL.getConnection().getTable(tableName);</span>
+<span class="source-line-no">172</span><span id="line-172">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">173</span><span id="line-173"></span>
+<span class="source-line-no">174</span><span id="line-174">      // split to 2 regions</span>
+<span class="source-line-no">175</span><span id="line-175">      admin.split(tableName, Bytes.toBytes("eee"));</span>
+<span class="source-line-no">176</span><span id="line-176">      blockUntilSplitFinished(UTIL, tableName, 2);</span>
+<span class="source-line-no">177</span><span id="line-177"></span>
+<span class="source-line-no">178</span><span id="line-178">      Path rootDir = CommonFSUtils.getRootDir(UTIL.getConfiguration());</span>
+<span class="source-line-no">179</span><span id="line-179">      FileSystem fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
+<span class="source-line-no">180</span><span id="line-180"></span>
+<span class="source-line-no">181</span><span id="line-181">      SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES),</span>
+<span class="source-line-no">182</span><span id="line-182">        null, snapshotName, rootDir, fs, true);</span>
+<span class="source-line-no">183</span><span id="line-183"></span>
+<span class="source-line-no">184</span><span id="line-184">      // load different values</span>
+<span class="source-line-no">185</span><span id="line-185">      byte[] value = Bytes.toBytes("after_snapshot_value");</span>
+<span class="source-line-no">186</span><span id="line-186">      UTIL.loadTable(table, FAMILIES, value);</span>
+<span class="source-line-no">187</span><span id="line-187"></span>
+<span class="source-line-no">188</span><span id="line-188">      // cause flush to create new files in the region</span>
+<span class="source-line-no">189</span><span id="line-189">      admin.flush(tableName);</span>
+<span class="source-line-no">190</span><span id="line-190">      table.close();</span>
+<span class="source-line-no">191</span><span id="line-191"></span>
+<span class="source-line-no">192</span><span id="line-192">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">193</span><span id="line-193">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">194</span><span id="line-194"></span>
+<span class="source-line-no">195</span><span id="line-195">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">196</span><span id="line-196">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">197</span><span id="line-197"></span>
+<span class="source-line-no">198</span><span id="line-198">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">199</span><span id="line-199">      scanner.close();</span>
+<span class="source-line-no">200</span><span id="line-200">    } catch (Exception e) {</span>
+<span class="source-line-no">201</span><span id="line-201">      e.printStackTrace();</span>
+<span class="source-line-no">202</span><span id="line-202">    } finally {</span>
+<span class="source-line-no">203</span><span id="line-203">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">204</span><span id="line-204">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">205</span><span id="line-205">    }</span>
+<span class="source-line-no">206</span><span id="line-206">  }</span>
+<span class="source-line-no">207</span><span id="line-207"></span>
+<span class="source-line-no">208</span><span id="line-208">  @Test</span>
+<span class="source-line-no">209</span><span id="line-209">  public void testScanLimit() throws Exception {</span>
+<span class="source-line-no">210</span><span id="line-210">    final TableName tableName = TableName.valueOf(methodName);</span>
+<span class="source-line-no">211</span><span id="line-211">    final String snapshotName = tableName + "Snapshot";</span>
+<span class="source-line-no">212</span><span id="line-212">    TableSnapshotScanner scanner = null;</span>
+<span class="source-line-no">213</span><span id="line-213">    try {</span>
+<span class="source-line-no">214</span><span id="line-214">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">215</span><span id="line-215">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">216</span><span id="line-216">      Scan scan = new Scan().withStartRow(bbb).setLimit(100); // limit the scan</span>
+<span class="source-line-no">217</span><span id="line-217"></span>
+<span class="source-line-no">218</span><span id="line-218">      scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">219</span><span id="line-219">      int count = 0;</span>
+<span class="source-line-no">220</span><span id="line-220">      while (true) {</span>
+<span class="source-line-no">221</span><span id="line-221">        Result result = scanner.next();</span>
+<span class="source-line-no">222</span><span id="line-222">        if (result == null) {</span>
+<span class="source-line-no">223</span><span id="line-223">          break;</span>
+<span class="source-line-no">224</span><span id="line-224">        }</span>
+<span class="source-line-no">225</span><span id="line-225">        count++;</span>
+<span class="source-line-no">226</span><span id="line-226">      }</span>
+<span class="source-line-no">227</span><span id="line-227">      assertEquals(100, count);</span>
+<span class="source-line-no">228</span><span id="line-228">    } finally {</span>
+<span class="source-line-no">229</span><span id="line-229">      if (scanner != null) {</span>
+<span class="source-line-no">230</span><span id="line-230">        scanner.close();</span>
+<span class="source-line-no">231</span><span id="line-231">      }</span>
+<span class="source-line-no">232</span><span id="line-232">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">233</span><span id="line-233">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">234</span><span id="line-234">    }</span>
+<span class="source-line-no">235</span><span id="line-235">  }</span>
+<span class="source-line-no">236</span><span id="line-236"></span>
+<span class="source-line-no">237</span><span id="line-237">  @Test</span>
+<span class="source-line-no">238</span><span id="line-238">  public void testWithSingleRegion() throws Exception {</span>
+<span class="source-line-no">239</span><span id="line-239">    testScanner(UTIL, "testWithSingleRegion", 1, false);</span>
+<span class="source-line-no">240</span><span id="line-240">  }</span>
+<span class="source-line-no">241</span><span id="line-241"></span>
+<span class="source-line-no">242</span><span id="line-242">  @Test</span>
+<span class="source-line-no">243</span><span id="line-243">  public void testWithMultiRegion() throws Exception {</span>
+<span class="source-line-no">244</span><span id="line-244">    testScanner(UTIL, "testWithMultiRegion", 10, false);</span>
+<span class="source-line-no">245</span><span id="line-245">  }</span>
+<span class="source-line-no">246</span><span id="line-246"></span>
+<span class="source-line-no">247</span><span id="line-247">  @Test</span>
+<span class="source-line-no">248</span><span id="line-248">  public void testWithOfflineHBaseMultiRegion() throws Exception {</span>
+<span class="source-line-no">249</span><span id="line-249">    testScanner(UTIL, "testWithMultiRegion", 20, true);</span>
+<span class="source-line-no">250</span><span id="line-250">  }</span>
+<span class="source-line-no">251</span><span id="line-251"></span>
+<span class="source-line-no">252</span><span id="line-252">  private ScanMetrics createTableSnapshotScannerAndGetScanMetrics(boolean enableScanMetrics,</span>
+<span class="source-line-no">253</span><span id="line-253">    boolean enableScanMetricsByRegion, byte[] endKey) throws Exception {</span>
+<span class="source-line-no">254</span><span id="line-254">    TableName tableName = TableName.valueOf(methodName + "_TABLE");</span>
+<span class="source-line-no">255</span><span id="line-255">    String snapshotName = methodName + "_SNAPSHOT";</span>
+<span class="source-line-no">256</span><span id="line-256">    try {</span>
+<span class="source-line-no">257</span><span id="line-257">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">258</span><span id="line-258">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">259</span><span id="line-259">      Scan scan = new Scan().withStartRow(bbb).withStopRow(endKey);</span>
+<span class="source-line-no">260</span><span id="line-260">      scan.setScanMetricsEnabled(enableScanMetrics);</span>
+<span class="source-line-no">261</span><span id="line-261">      scan.setEnableScanMetricsByRegion(enableScanMetricsByRegion);</span>
+<span class="source-line-no">262</span><span id="line-262">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">263</span><span id="line-263"></span>
+<span class="source-line-no">264</span><span id="line-264">      TableSnapshotScanner snapshotScanner =</span>
+<span class="source-line-no">265</span><span id="line-265">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">266</span><span id="line-266">      verifyScanner(snapshotScanner, bbb, endKey);</span>
+<span class="source-line-no">267</span><span id="line-267">      return snapshotScanner.getScanMetrics();</span>
+<span class="source-line-no">268</span><span id="line-268">    } finally {</span>
+<span class="source-line-no">269</span><span id="line-269">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">270</span><span id="line-270">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">271</span><span id="line-271">    }</span>
+<span class="source-line-no">272</span><span id="line-272">  }</span>
+<span class="source-line-no">273</span><span id="line-273"></span>
+<span class="source-line-no">274</span><span id="line-274">  @Test</span>
+<span class="source-line-no">275</span><span id="line-275">  public void testScanMetricsDisabled() throws Exception {</span>
+<span class="source-line-no">276</span><span id="line-276">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(false, false, yyy);</span>
+<span class="source-line-no">277</span><span id="line-277">    assertNull(scanMetrics);</span>
+<span class="source-line-no">278</span><span id="line-278">  }</span>
+<span class="source-line-no">279</span><span id="line-279"></span>
+<span class="source-line-no">280</span><span id="line-280">  @Test</span>
+<span class="source-line-no">281</span><span id="line-281">  public void testScanMetricsWithScanMetricsByRegionDisabled() throws Exception {</span>
+<span class="source-line-no">282</span><span id="line-282">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, false, yyy);</span>
+<span class="source-line-no">283</span><span id="line-283">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">284</span><span id="line-284">    int rowsScanned = 0;</span>
+<span class="source-line-no">285</span><span id="line-285">    for (byte[] row : HBaseTestingUtil.ROWS) {</span>
+<span class="source-line-no">286</span><span id="line-286">      if (Bytes.compareTo(row, bbb) &gt;= 0 &amp;&amp; Bytes.compareTo(row, yyy) &lt; 0) {</span>
+<span class="source-line-no">287</span><span id="line-287">        rowsScanned++;</span>
+<span class="source-line-no">288</span><span id="line-288">      }</span>
+<span class="source-line-no">289</span><span id="line-289">    }</span>
+<span class="source-line-no">290</span><span id="line-290">    Map&lt;String, Long&gt; metricsMap = scanMetrics.getMetricsMap();</span>
+<span class="source-line-no">291</span><span id="line-291">    assertEquals(rowsScanned, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
+<span class="source-line-no">292</span><span id="line-292">  }</span>
+<span class="source-line-no">293</span><span id="line-293"></span>
+<span class="source-line-no">294</span><span id="line-294">  @Test</span>
+<span class="source-line-no">295</span><span id="line-295">  public void testScanMetricsByRegionForSingleRegion() throws Exception {</span>
+<span class="source-line-no">296</span><span id="line-296">    // Scan single row with row key bbb</span>
+<span class="source-line-no">297</span><span id="line-297">    byte[] bbc = Bytes.toBytes("bbc");</span>
+<span class="source-line-no">298</span><span id="line-298">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, bbc);</span>
+<span class="source-line-no">299</span><span id="line-299">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">300</span><span id="line-300">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
+<span class="source-line-no">301</span><span id="line-301">      scanMetrics.collectMetricsByRegion();</span>
+<span class="source-line-no">302</span><span id="line-302">    assertEquals(1, scanMetricsByRegion.size());</span>
+<span class="source-line-no">303</span><span id="line-303">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
+<span class="source-line-no">304</span><span id="line-304">      .entrySet()) {</span>
+<span class="source-line-no">305</span><span id="line-305">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
+<span class="source-line-no">306</span><span id="line-306">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
+<span class="source-line-no">307</span><span id="line-307">      assertNull(scanMetricsRegionInfo.getServerName());</span>
+<span class="source-line-no">308</span><span id="line-308">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
+<span class="source-line-no">309</span><span id="line-309">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
+<span class="source-line-no">310</span><span id="line-310">      assertEquals(1, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
+<span class="source-line-no">311</span><span id="line-311">    }</span>
+<span class="source-line-no">312</span><span id="line-312">  }</span>
+<span class="source-line-no">313</span><span id="line-313"></span>
+<span class="source-line-no">314</span><span id="line-314">  @Test</span>
+<span class="source-line-no">315</span><span id="line-315">  public void testScanMetricsByRegionForMultiRegion() throws Exception {</span>
+<span class="source-line-no">316</span><span id="line-316">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, yyy);</span>
+<span class="source-line-no">317</span><span id="line-317">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">318</span><span id="line-318">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
+<span class="source-line-no">319</span><span id="line-319">      scanMetrics.collectMetricsByRegion();</span>
+<span class="source-line-no">320</span><span id="line-320">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
+<span class="source-line-no">321</span><span id="line-321">      .entrySet()) {</span>
+<span class="source-line-no">322</span><span id="line-322">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
+<span class="source-line-no">323</span><span id="line-323">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
+<span class="source-line-no">324</span><span id="line-324">      assertNull(scanMetricsRegionInfo.getServerName());</span>
+<span class="source-line-no">325</span><span id="line-325">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
+<span class="source-line-no">326</span><span id="line-326">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
+<span class="source-line-no">327</span><span id="line-327">    }</span>
+<span class="source-line-no">328</span><span id="line-328">  }</span>
+<span class="source-line-no">329</span><span id="line-329"></span>
+<span class="source-line-no">330</span><span id="line-330">  @Test</span>
+<span class="source-line-no">331</span><span id="line-331">  public void testScannerWithRestoreScanner() throws Exception {</span>
+<span class="source-line-no">332</span><span id="line-332">    TableName tableName = TableName.valueOf("testScanner");</span>
+<span class="source-line-no">333</span><span id="line-333">    String snapshotName = "testScannerWithRestoreScanner";</span>
+<span class="source-line-no">334</span><span id="line-334">    try {</span>
+<span class="source-line-no">335</span><span id="line-335">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">336</span><span id="line-336">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">337</span><span id="line-337">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">338</span><span id="line-338"></span>
+<span class="source-line-no">339</span><span id="line-339">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">340</span><span id="line-340">      Path rootDir = CommonFSUtils.getRootDir(conf);</span>
+<span class="source-line-no">341</span><span id="line-341"></span>
+<span class="source-line-no">342</span><span id="line-342">      TableSnapshotScanner scanner0 =</span>
+<span class="source-line-no">343</span><span id="line-343">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">344</span><span id="line-344">      verifyScanner(scanner0, bbb, yyy);</span>
+<span class="source-line-no">345</span><span id="line-345">      scanner0.close();</span>
+<span class="source-line-no">346</span><span id="line-346"></span>
+<span class="source-line-no">347</span><span id="line-347">      // restore snapshot.</span>
+<span class="source-line-no">348</span><span id="line-348">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">349</span><span id="line-349"></span>
+<span class="source-line-no">350</span><span id="line-350">      // scan the snapshot without restoring snapshot</span>
+<span class="source-line-no">351</span><span id="line-351">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">352</span><span id="line-352">        new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">353</span><span id="line-353">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">354</span><span id="line-354">      scanner.close();</span>
+<span class="source-line-no">355</span><span id="line-355"></span>
+<span class="source-line-no">356</span><span id="line-356">      // check whether the snapshot has been deleted by the close of scanner.</span>
+<span class="source-line-no">357</span><span id="line-357">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">358</span><span id="line-358">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">359</span><span id="line-359">      scanner.close();</span>
+<span class="source-line-no">360</span><span id="line-360"></span>
+<span class="source-line-no">361</span><span id="line-361">      // restore snapshot again.</span>
+<span class="source-line-no">362</span><span id="line-362">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">363</span><span id="line-363"></span>
+<span class="source-line-no">364</span><span id="line-364">      // check whether the snapshot has been deleted by the close of scanner.</span>
+<span class="source-line-no">365</span><span id="line-365">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">366</span><span id="line-366">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">367</span><span id="line-367">      scanner.close();</span>
+<span class="source-line-no">368</span><span id="line-368">    } finally {</span>
+<span class="source-line-no">369</span><span id="line-369">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">370</span><span id="line-370">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">371</span><span id="line-371">    }</span>
+<span class="source-line-no">372</span><span id="line-372">  }</span>
+<span class="source-line-no">373</span><span id="line-373"></span>
+<span class="source-line-no">374</span><span id="line-374">  @Test</span>
+<span class="source-line-no">375</span><span id="line-375">  public void testScannerWithRestoredMobSnapshot() throws Exception {</span>
+<span class="source-line-no">376</span><span id="line-376">    TableName tableName = TableName.valueOf(methodName);</span>
+<span class="source-line-no">377</span><span id="line-377">    String snapshotName = methodName + "Snapshot";</span>
+<span class="source-line-no">378</span><span id="line-378">    Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">379</span><span id="line-379">    try {</span>
+<span class="source-line-no">380</span><span id="line-380">      MobSnapshotTestingUtils.createMobTable(UTIL, tableName, new byte[0][], 1, FAMILIES);</span>
+<span class="source-line-no">381</span><span id="line-381">      try (Table table = UTIL.getConnection().getTable(tableName)) {</span>
+<span class="source-line-no">382</span><span id="line-382">        UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">383</span><span id="line-383">      }</span>
+<span class="source-line-no">384</span><span id="line-384">      UTIL.getAdmin().snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">385</span><span id="line-385"></span>
+<span class="source-line-no">386</span><span id="line-386">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">387</span><span id="line-387">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">388</span><span id="line-388">      try (TableSnapshotScanner scanner = new TableSnapshotScanner(conf, rootDir, restoreDir,</span>
+<span class="source-line-no">389</span><span id="line-389">        snapshotName, new Scan().withStartRow(Bytes.toBytes("zzzz")), true)) {</span>
+<span class="source-line-no">390</span><span id="line-390">        assertNull(scanner.next());</span>
+<span class="source-line-no">391</span><span id="line-391">      }</span>
 <span class="source-line-no">392</span><span id="line-392">    } finally {</span>
-<span class="source-line-no">393</span><span id="line-393">      if (clusterUp) {</span>
-<span class="source-line-no">394</span><span id="line-394">        util.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">395</span><span id="line-395">        util.deleteTable(tableName);</span>
-<span class="source-line-no">396</span><span id="line-396">      }</span>
-<span class="source-line-no">397</span><span id="line-397">    }</span>
-<span class="source-line-no">398</span><span id="line-398">  }</span>
-<span class="source-line-no">399</span><span id="line-399"></span>
-<span class="source-line-no">400</span><span id="line-400">  private void verifyScanner(ResultScanner scanner, byte[] startRow, byte[] stopRow)</span>
-<span class="source-line-no">401</span><span id="line-401">    throws IOException, InterruptedException {</span>
-<span class="source-line-no">402</span><span id="line-402"></span>
-<span class="source-line-no">403</span><span id="line-403">    HBaseTestingUtil.SeenRowTracker rowTracker =</span>
-<span class="source-line-no">404</span><span id="line-404">      new HBaseTestingUtil.SeenRowTracker(startRow, stopRow);</span>
-<span class="source-line-no">405</span><span id="line-405"></span>
-<span class="source-line-no">406</span><span id="line-406">    while (true) {</span>
-<span class="source-line-no">407</span><span id="line-407">      Result result = scanner.next();</span>
-<span class="source-line-no">408</span><span id="line-408">      if (result == null) {</span>
-<span class="source-line-no">409</span><span id="line-409">        break;</span>
-<span class="source-line-no">410</span><span id="line-410">      }</span>
-<span class="source-line-no">411</span><span id="line-411">      verifyRow(result);</span>
-<span class="source-line-no">412</span><span id="line-412">      rowTracker.addRow(result.getRow());</span>
-<span class="source-line-no">413</span><span id="line-413">    }</span>
-<span class="source-line-no">414</span><span id="line-414"></span>
-<span class="source-line-no">415</span><span id="line-415">    // validate all rows are seen</span>
-<span class="source-line-no">416</span><span id="line-416">    rowTracker.validate();</span>
-<span class="source-line-no">417</span><span id="line-417">  }</span>
-<span class="source-line-no">418</span><span id="line-418"></span>
-<span class="source-line-no">419</span><span id="line-419">  private static void verifyRow(Result result) throws IOException {</span>
-<span class="source-line-no">420</span><span id="line-420">    byte[] row = result.getRow();</span>
-<span class="source-line-no">421</span><span id="line-421">    CellScanner scanner = result.cellScanner();</span>
-<span class="source-line-no">422</span><span id="line-422">    while (scanner.advance()) {</span>
-<span class="source-line-no">423</span><span id="line-423">      Cell cell = scanner.current();</span>
-<span class="source-line-no">424</span><span id="line-424"></span>
-<span class="source-line-no">425</span><span id="line-425">      // assert that all Cells in the Result have the same key</span>
-<span class="source-line-no">426</span><span id="line-426">      assertEquals(0, Bytes.compareTo(row, 0, row.length, cell.getRowArray(), cell.getRowOffset(),</span>
-<span class="source-line-no">427</span><span id="line-427">        cell.getRowLength()));</span>
-<span class="source-line-no">428</span><span id="line-428">    }</span>
-<span class="source-line-no">429</span><span id="line-429"></span>
-<span class="source-line-no">430</span><span id="line-430">    for (int j = 0; j &lt; FAMILIES.length; j++) {</span>
-<span class="source-line-no">431</span><span id="line-431">      byte[] actual = result.getValue(FAMILIES[j], FAMILIES[j]);</span>
-<span class="source-line-no">432</span><span id="line-432">      assertArrayEquals(row, actual, "Row in snapshot does not match, expected:"</span>
-<span class="source-line-no">433</span><span id="line-433">        + Bytes.toString(row) + " ,actual:" + Bytes.toString(actual));</span>
-<span class="source-line-no">434</span><span id="line-434">    }</span>
-<span class="source-line-no">435</span><span id="line-435">  }</span>
-<span class="source-line-no">436</span><span id="line-436"></span>
-<span class="source-line-no">437</span><span id="line-437">  @Test</span>
-<span class="source-line-no">438</span><span id="line-438">  public void testMergeRegion() throws Exception {</span>
-<span class="source-line-no">439</span><span id="line-439">    TableName tableName = TableName.valueOf("testMergeRegion");</span>
-<span class="source-line-no">440</span><span id="line-440">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
-<span class="source-line-no">441</span><span id="line-441">    Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">442</span><span id="line-442">    Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
-<span class="source-line-no">443</span><span id="line-443">    long timeout = 20000; // 20s</span>
-<span class="source-line-no">444</span><span id="line-444">    try (Admin admin = UTIL.getAdmin()) {</span>
-<span class="source-line-no">445</span><span id="line-445">      List&lt;String&gt; serverList = admin.getRegionServers().stream().map(sn -&gt; sn.getServerName())</span>
-<span class="source-line-no">446</span><span id="line-446">        .collect(Collectors.toList());</span>
-<span class="source-line-no">447</span><span id="line-447">      // create table with 3 regions</span>
-<span class="source-line-no">448</span><span id="line-448">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
-<span class="source-line-no">449</span><span id="line-449">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">450</span><span id="line-450">      assertEquals(3, regions.size());</span>
-<span class="source-line-no">451</span><span id="line-451">      RegionInfo region0 = regions.get(0);</span>
-<span class="source-line-no">452</span><span id="line-452">      RegionInfo region1 = regions.get(1);</span>
-<span class="source-line-no">453</span><span id="line-453">      RegionInfo region2 = regions.get(2);</span>
-<span class="source-line-no">454</span><span id="line-454">      // put some data in the table</span>
-<span class="source-line-no">455</span><span id="line-455">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">456</span><span id="line-456">      admin.flush(tableName);</span>
-<span class="source-line-no">457</span><span id="line-457">      // wait flush is finished</span>
-<span class="source-line-no">458</span><span id="line-458">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">459</span><span id="line-459">        try {</span>
-<span class="source-line-no">460</span><span id="line-460">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">461</span><span id="line-461">          for (RegionInfo region : regions) {</span>
-<span class="source-line-no">462</span><span id="line-462">            Path regionDir = new Path(tableDir, region.getEncodedName());</span>
-<span class="source-line-no">463</span><span id="line-463">            for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
-<span class="source-line-no">464</span><span id="line-464">              for (FileStatus fs : fs.listStatus(familyDir)) {</span>
-<span class="source-line-no">465</span><span id="line-465">                if (!fs.getPath().getName().equals(".filelist")) {</span>
-<span class="source-line-no">466</span><span id="line-466">                  return true;</span>
-<span class="source-line-no">467</span><span id="line-467">                }</span>
-<span class="source-line-no">468</span><span id="line-468">              }</span>
-<span class="source-line-no">469</span><span id="line-469">              return false;</span>
-<span class="source-line-no">470</span><span id="line-470">            }</span>
-<span class="source-line-no">471</span><span id="line-471">          }</span>
-<span class="source-line-no">472</span><span id="line-472">          return true;</span>
-<span class="source-line-no">473</span><span id="line-473">        } catch (IOException e) {</span>
-<span class="source-line-no">474</span><span id="line-474">          LOG.warn("Failed check if flush is finished", e);</span>
-<span class="source-line-no">475</span><span id="line-475">          return false;</span>
-<span class="source-line-no">476</span><span id="line-476">        }</span>
-<span class="source-line-no">477</span><span id="line-477">      });</span>
-<span class="source-line-no">478</span><span id="line-478">      // merge 2 regions</span>
-<span class="source-line-no">479</span><span id="line-479">      admin.compactionSwitch(false, serverList);</span>
-<span class="source-line-no">480</span><span id="line-480">      admin.mergeRegionsAsync(region0.getEncodedNameAsBytes(), region1.getEncodedNameAsBytes(),</span>
-<span class="source-line-no">481</span><span id="line-481">        true);</span>
-<span class="source-line-no">482</span><span id="line-482">      UTIL.waitFor(timeout, () -&gt; admin.getRegions(tableName).size() == 2);</span>
-<span class="source-line-no">483</span><span id="line-483">      List&lt;RegionInfo&gt; mergedRegions = admin.getRegions(tableName);</span>
-<span class="source-line-no">484</span><span id="line-484">      RegionInfo mergedRegion =</span>
-<span class="source-line-no">485</span><span id="line-485">        mergedRegions.get(0).getEncodedName().equals(region2.getEncodedName())</span>
-<span class="source-line-no">486</span><span id="line-486">          ? mergedRegions.get(1)</span>
-<span class="source-line-no">487</span><span id="line-487">          : mergedRegions.get(0);</span>
-<span class="source-line-no">488</span><span id="line-488">      // snapshot</span>
-<span class="source-line-no">489</span><span id="line-489">      admin.snapshot(snapshotName, tableName);</span>
-<span class="source-line-no">490</span><span id="line-490">      assertEquals(1, admin.listSnapshots().size());</span>
-<span class="source-line-no">491</span><span id="line-491">      // major compact</span>
-<span class="source-line-no">492</span><span id="line-492">      admin.compactionSwitch(true, serverList);</span>
-<span class="source-line-no">493</span><span id="line-493">      admin.majorCompactRegion(mergedRegion.getRegionName());</span>
-<span class="source-line-no">494</span><span id="line-494">      // wait until merged region has no reference</span>
-<span class="source-line-no">495</span><span id="line-495">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">496</span><span id="line-496">        try {</span>
-<span class="source-line-no">497</span><span id="line-497">          for (RegionServerThread regionServerThread : UTIL.getMiniHBaseCluster()</span>
-<span class="source-line-no">498</span><span id="line-498">            .getRegionServerThreads()) {</span>
-<span class="source-line-no">499</span><span id="line-499">            HRegionServer regionServer = regionServerThread.getRegionServer();</span>
-<span class="source-line-no">500</span><span id="line-500">            for (HRegion subRegion : regionServer.getRegions(tableName)) {</span>
-<span class="source-line-no">501</span><span id="line-501">              if (</span>
-<span class="source-line-no">502</span><span id="line-502">                subRegion.getRegionInfo().getEncodedName().equals(mergedRegion.getEncodedName())</span>
-<span class="source-line-no">503</span><span id="line-503">              ) {</span>
-<span class="source-line-no">504</span><span id="line-504">                regionServer.getCompactedHFilesDischarger().chore();</span>
-<span class="source-line-no">505</span><span id="line-505">              }</span>
-<span class="source-line-no">506</span><span id="line-506">            }</span>
-<span class="source-line-no">507</span><span id="line-507">          }</span>
-<span class="source-line-no">508</span><span id="line-508">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">509</span><span id="line-509">          HRegionFileSystem regionFs = HRegionFileSystem</span>
-<span class="source-line-no">510</span><span id="line-510">            .openRegionFromFileSystem(UTIL.getConfiguration(), fs, tableDir, mergedRegion, true);</span>
-<span class="source-line-no">511</span><span id="line-511">          boolean references = false;</span>
-<span class="source-line-no">512</span><span id="line-512">          Path regionDir = new Path(tableDir, mergedRegion.getEncodedName());</span>
-<span class="source-line-no">513</span><span id="line-513">          for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
-<span class="source-line-no">514</span><span id="line-514">            StoreContext storeContext = StoreContext.getBuilder()</span>
-<span class="source-line-no">515</span><span id="line-515">              .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.of(familyDir.getName()))</span>
-<span class="source-line-no">516</span><span id="line-516">              .withRegionFileSystem(regionFs).withFamilyStoreDirectoryPath(familyDir).build();</span>
-<span class="source-line-no">517</span><span id="line-517">            StoreFileTracker sft =</span>
-<span class="source-line-no">518</span><span id="line-518">              StoreFileTrackerFactory.create(UTIL.getConfiguration(), false, storeContext);</span>
-<span class="source-line-no">519</span><span id="line-519">            references = references || sft.hasReferences();</span>
-<span class="source-line-no">520</span><span id="line-520">            if (references) {</span>
-<span class="source-line-no">521</span><span id="line-521">              break;</span>
-<span class="source-line-no">522</span><span id="line-522">            }</span>
-<span class="source-line-no">523</span><span id="line-523">          }</span>
-<span class="source-line-no">524</span><span id="line-524">          return !references;</span>
-<span class="source-line-no">525</span><span id="line-525">        } catch (IOException e) {</span>
-<span class="source-line-no">526</span><span id="line-526">          LOG.warn("Failed check merged region has no reference", e);</span>
-<span class="source-line-no">527</span><span id="line-527">          return false;</span>
-<span class="source-line-no">528</span><span id="line-528">        }</span>
-<span class="source-line-no">529</span><span id="line-529">      });</span>
-<span class="source-line-no">530</span><span id="line-530">      // run catalog janitor to clean and wait for parent regions are archived</span>
-<span class="source-line-no">531</span><span id="line-531">      UTIL.getMiniHBaseCluster().getMaster().getCatalogJanitor().choreForTesting();</span>
-<span class="source-line-no">532</span><span id="line-532">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">533</span><span id="line-533">        try {</span>
+<span class="source-line-no">393</span><span id="line-393">      fs.delete(restoreDir, true);</span>
+<span class="source-line-no">394</span><span id="line-394">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">395</span><span id="line-395">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">396</span><span id="line-396">    }</span>
+<span class="source-line-no">397</span><span id="line-397">  }</span>
+<span class="source-line-no">398</span><span id="line-398"></span>
+<span class="source-line-no">399</span><span id="line-399">  private void testScanner(HBaseTestingUtil util, String snapshotName, int numRegions,</span>
+<span class="source-line-no">400</span><span id="line-400">    boolean shutdownCluster) throws Exception {</span>
+<span class="source-line-no">401</span><span id="line-401">    TableName tableName = TableName.valueOf("testScanner");</span>
+<span class="source-line-no">402</span><span id="line-402">    try {</span>
+<span class="source-line-no">403</span><span id="line-403">      createTableAndSnapshot(util, tableName, snapshotName, numRegions);</span>
+<span class="source-line-no">404</span><span id="line-404"></span>
+<span class="source-line-no">405</span><span id="line-405">      if (shutdownCluster) {</span>
+<span class="source-line-no">406</span><span id="line-406">        util.shutdownMiniHBaseCluster();</span>
+<span class="source-line-no">407</span><span id="line-407">        clusterUp = false;</span>
+<span class="source-line-no">408</span><span id="line-408">      }</span>
+<span class="source-line-no">409</span><span id="line-409"></span>
+<span class="source-line-no">410</span><span id="line-410">      Path restoreDir = util.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">411</span><span id="line-411">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">412</span><span id="line-412"></span>
+<span class="source-line-no">413</span><span id="line-413">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">414</span><span id="line-414">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">415</span><span id="line-415"></span>
+<span class="source-line-no">416</span><span id="line-416">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">417</span><span id="line-417">      scanner.close();</span>
+<span class="source-line-no">418</span><span id="line-418">    } finally {</span>
+<span class="source-line-no">419</span><span id="line-419">      if (clusterUp) {</span>
+<span class="source-line-no">420</span><span id="line-420">        util.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">421</span><span id="line-421">        util.deleteTable(tableName);</span>
+<span class="source-line-no">422</span><span id="line-422">      }</span>
+<span class="source-line-no">423</span><span id="line-423">    }</span>
+<span class="source-line-no">424</span><span id="line-424">  }</span>
+<span class="source-line-no">425</span><span id="line-425"></span>
+<span class="source-line-no">426</span><span id="line-426">  private void verifyScanner(ResultScanner scanner, byte[] startRow, byte[] stopRow)</span>
+<span class="source-line-no">427</span><span id="line-427">    throws IOException, InterruptedException {</span>
+<span class="source-line-no">428</span><span id="line-428"></span>
+<span class="source-line-no">429</span><span id="line-429">    HBaseTestingUtil.SeenRowTracker rowTracker =</span>
+<span class="source-line-no">430</span><span id="line-430">      new HBaseTestingUtil.SeenRowTracker(startRow, stopRow);</span>
+<span class="source-line-no">431</span><span id="line-431"></span>
+<span class="source-line-no">432</span><span id="line-432">    while (true) {</span>
+<span class="source-line-no">433</span><span id="line-433">      Result result = scanner.next();</span>
+<span class="source-line-no">434</span><span id="line-434">      if (result == null) {</span>
+<span class="source-line-no">435</span><span id="line-435">        break;</span>
+<span class="source-line-no">436</span><span id="line-436">      }</span>
+<span class="source-line-no">437</span><span id="line-437">      verifyRow(result);</span>
+<span class="source-line-no">438</span><span id="line-438">      rowTracker.addRow(result.getRow());</span>
+<span class="source-line-no">439</span><span id="line-439">    }</span>
+<span class="source-line-no">440</span><span id="line-440"></span>
+<span class="source-line-no">441</span><span id="line-441">    // validate all rows are seen</span>
+<span class="source-line-no">442</span><span id="line-442">    rowTracker.validate();</span>
+<span class="source-line-no">443</span><span id="line-443">  }</span>
+<span class="source-line-no">444</span><span id="line-444"></span>
+<span class="source-line-no">445</span><span id="line-445">  private static void verifyRow(Result result) throws IOException {</span>
+<span class="source-line-no">446</span><span id="line-446">    byte[] row = result.getRow();</span>
+<span class="source-line-no">447</span><span id="line-447">    CellScanner scanner = result.cellScanner();</span>
+<span class="source-line-no">448</span><span id="line-448">    while (scanner.advance()) {</span>
+<span class="source-line-no">449</span><span id="line-449">      Cell cell = scanner.current();</span>
+<span class="source-line-no">450</span><span id="line-450"></span>
+<span class="source-line-no">451</span><span id="line-451">      // assert that all Cells in the Result have the same key</span>
+<span class="source-line-no">452</span><span id="line-452">      assertEquals(0, Bytes.compareTo(row, 0, row.length, cell.getRowArray(), cell.getRowOffset(),</span>
+<span class="source-line-no">453</span><span id="line-453">        cell.getRowLength()));</span>
+<span class="source-line-no">454</span><span id="line-454">    }</span>
+<span class="source-line-no">455</span><span id="line-455"></span>
+<span class="source-line-no">456</span><span id="line-456">    for (int j = 0; j &lt; FAMILIES.length; j++) {</span>
+<span class="source-line-no">457</span><span id="line-457">      byte[] actual = result.getValue(FAMILIES[j], FAMILIES[j]);</span>
+<span class="source-line-no">458</span><span id="line-458">      assertArrayEquals(row, actual, "Row in snapshot does not match, expected:"</span>
+<span class="source-line-no">459</span><span id="line-459">        + Bytes.toString(row) + " ,actual:" + Bytes.toString(actual));</span>
+<span class="source-line-no">460</span><span id="line-460">    }</span>
+<span class="source-line-no">461</span><span id="line-461">  }</span>
+<span class="source-line-no">462</span><span id="line-462"></span>
+<span class="source-line-no">463</span><span id="line-463">  @Test</span>
+<span class="source-line-no">464</span><span id="line-464">  public void testMergeRegion() throws Exception {</span>
+<span class="source-line-no">465</span><span id="line-465">    TableName tableName = TableName.valueOf("testMergeRegion");</span>
+<span class="source-line-no">466</span><span id="line-466">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
+<span class="source-line-no">467</span><span id="line-467">    Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">468</span><span id="line-468">    Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
+<span class="source-line-no">469</span><span id="line-469">    long timeout = 20000; // 20s</span>
+<span class="source-line-no">470</span><span id="line-470">    try (Admin admin = UTIL.getAdmin()) {</span>
+<span class="source-line-no">471</span><span id="line-471">      List&lt;String&gt; serverList = admin.getRegionServers().stream().map(sn -&gt; sn.getServerName())</span>
+<span class="source-line-no">472</span><span id="line-472">        .collect(Collectors.toList());</span>
+<span class="source-line-no">473</span><span id="line-473">      // create table with 3 regions</span>
+<span class="source-line-no">474</span><span id="line-474">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
+<span class="source-line-no">475</span><span id="line-475">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">476</span><span id="line-476">      assertEquals(3, regions.size());</span>
+<span class="source-line-no">477</span><span id="line-477">      RegionInfo region0 = regions.get(0);</span>
+<span class="source-line-no">478</span><span id="line-478">      RegionInfo region1 = regions.get(1);</span>
+<span class="source-line-no">479</span><span id="line-479">      RegionInfo region2 = regions.get(2);</span>
+<span class="source-line-no">480</span><span id="line-480">      // put some data in the table</span>
+<span class="source-line-no">481</span><span id="line-481">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">482</span><span id="line-482">      admin.flush(tableName);</span>
+<span class="source-line-no">483</span><span id="line-483">      // wait flush is finished</span>
+<span class="source-line-no">484</span><span id="line-484">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">485</span><span id="line-485">        try {</span>
+<span class="source-line-no">486</span><span id="line-486">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
+<span class="source-line-no">487</span><span id="line-487">          for (RegionInfo region : regions) {</span>
+<span class="source-line-no">488</span><span id="line-488">            Path regionDir = new Path(tableDir, region.getEncodedName());</span>
+<span class="source-line-no">489</span><span id="line-489">            for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
+<span class="source-line-no">490</span><span id="line-490">              for (FileStatus fs : fs.listStatus(familyDir)) {</span>
+<span class="source-line-no">491</span><span id="line-491">                if (!fs.getPath().getName().equals(".filelist")) {</span>
+<span class="source-line-no">492</span><span id="line-492">                  return true;</span>
+<span class="source-line-no">493</span><span id="line-493">                }</span>
+<span class="source-line-no">494</span><span id="line-494">              }</span>
+<span class="source-line-no">495</span><span id="line-495">              return false;</span>
+<span class="source-line-no">496</span><span id="line-496">            }</span>
+<span class="source-line-no">497</span><span id="line-497">          }</span>
+<span class="source-line-no">498</span><span id="line-498">          return true;</span>
+<span class="source-line-no">499</span><span id="line-499">        } catch (IOException e) {</span>
+<span class="source-line-no">500</span><span id="line-500">          LOG.warn("Failed check if flush is finished", e);</span>
+<span class="source-line-no">501</span><span id="line-501">          return false;</span>
+<span class="source-line-no">502</span><span id="line-502">        }</span>
+<span class="source-line-no">503</span><span id="line-503">      });</span>
+<span class="source-line-no">504</span><span id="line-504">      // merge 2 regions</span>
+<span class="source-line-no">505</span><span id="line-505">      admin.compactionSwitch(false, serverList);</span>
+<span class="source-line-no">506</span><span id="line-506">      admin.mergeRegionsAsync(region0.getEncodedNameAsBytes(), region1.getEncodedNameAsBytes(),</span>
+<span class="source-line-no">507</span><span id="line-507">        true);</span>
+<span class="source-line-no">508</span><span id="line-508">      UTIL.waitFor(timeout, () -&gt; admin.getRegions(tableName).size() == 2);</span>
+<span class="source-line-no">509</span><span id="line-509">      List&lt;RegionInfo&gt; mergedRegions = admin.getRegions(tableName);</span>
+<span class="source-line-no">510</span><span id="line-510">      RegionInfo mergedRegion =</span>
+<span class="source-line-no">511</span><span id="line-511">        mergedRegions.get(0).getEncodedName().equals(region2.getEncodedName())</span>
+<span class="source-line-no">512</span><span id="line-512">          ? mergedRegions.get(1)</span>
+<span class="source-line-no">513</span><span id="line-513">          : mergedRegions.get(0);</span>
+<span class="source-line-no">514</span><span id="line-514">      // snapshot</span>
+<span class="source-line-no">515</span><span id="line-515">      admin.snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">516</span><span id="line-516">      assertEquals(1, admin.listSnapshots().size());</span>
+<span class="source-line-no">517</span><span id="line-517">      // major compact</span>
+<span class="source-line-no">518</span><span id="line-518">      admin.compactionSwitch(true, serverList);</span>
+<span class="source-line-no">519</span><span id="line-519">      admin.majorCompactRegion(mergedRegion.getRegionName());</span>
+<span class="source-line-no">520</span><span id="line-520">      // wait until merged region has no reference</span>
+<span class="source-line-no">521</span><span id="line-521">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">522</span><span id="line-522">        try {</span>
+<span class="source-line-no">523</span><span id="line-523">          for (RegionServerThread regionServerThread : UTIL.getMiniHBaseCluster()</span>
+<span class="source-line-no">524</span><span id="line-524">            .getRegionServerThreads()) {</span>
+<span class="source-line-no">525</span><span id="line-525">            HRegionServer regionServer = regionServerThread.getRegionServer();</span>
+<span class="source-line-no">526</span><span id="line-526">            for (HRegion subRegion : regionServer.getRegions(tableName)) {</span>
+<span class="source-line-no">527</span><span id="line-527">              if (</span>
+<span class="source-line-no">528</span><span id="line-528">                subRegion.getRegionInfo().getEncodedName().equals(mergedRegion.getEncodedName())</span>
+<span class="source-line-no">529</span><span id="line-529">              ) {</span>
+<span class="source-line-no">530</span><span id="line-530">                regionServer.getCompactedHFilesDischarger().chore();</span>
+<span class="source-line-no">531</span><span id="line-531">              }</span>
+<span class="source-line-no">532</span><span id="line-532">            }</span>
+<span class="source-line-no">533</span><span id="line-533">          }</span>
 <span class="source-line-no">534</span><span id="line-534">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">535</span><span id="line-535">          for (FileStatus fileStatus : fs.listStatus(tableDir)) {</span>
-<span class="source-line-no">536</span><span id="line-536">            String name = fileStatus.getPath().getName();</span>
-<span class="source-line-no">537</span><span id="line-537">            if (name.equals(region0.getEncodedName()) || name.equals(region1.getEncodedName())) {</span>
-<span class="source-line-no">538</span><span id="line-538">              return false;</span>
-<span class="source-line-no">539</span><span id="line-539">            }</span>
-<span class="source-line-no">540</span><span id="line-540">          }</span>
-<span class="source-line-no">541</span><span id="line-541">          return true;</span>
-<span class="source-line-no">542</span><span id="line-542">        } catch (IOException e) {</span>
-<span class="source-line-no">543</span><span id="line-543">          LOG.warn("Check if parent regions are archived error", e);</span>
-<span class="source-line-no">544</span><span id="line-544">          return false;</span>
-<span class="source-line-no">545</span><span id="line-545">        }</span>
-<span class="source-line-no">546</span><span id="line-546">      });</span>
-<span class="source-line-no">547</span><span id="line-547">      // set file modify time and then run cleaner</span>
-<span class="source-line-no">548</span><span id="line-548">      long time = EnvironmentEdgeManager.currentTime() - TimeToLiveHFileCleaner.DEFAULT_TTL * 1000;</span>
-<span class="source-line-no">549</span><span id="line-549">      traverseAndSetFileTime(HFileArchiveUtil.getArchivePath(conf), time);</span>
-<span class="source-line-no">550</span><span id="line-550">      UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().triggerCleanerNow().get();</span>
-<span class="source-line-no">551</span><span id="line-551">      // scan snapshot</span>
-<span class="source-line-no">552</span><span id="line-552">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">553</span><span id="line-553">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">554</span><span id="line-554">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">555</span><span id="line-555">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">556</span><span id="line-556">      }</span>
-<span class="source-line-no">557</span><span id="line-557">    } catch (Exception e) {</span>
-<span class="source-line-no">558</span><span id="line-558">      LOG.error("scan snapshot error", e);</span>
-<span class="source-line-no">559</span><span id="line-559">      fail("Should not throw Exception: " + e.getMessage());</span>
-<span class="source-line-no">560</span><span id="line-560">    }</span>
-<span class="source-line-no">561</span><span id="line-561">  }</span>
-<span class="source-line-no">562</span><span id="line-562"></span>
-<span class="source-line-no">563</span><span id="line-563">  @Test</span>
-<span class="source-line-no">564</span><span id="line-564">  public void testDeleteTableWithMergedRegions() throws Exception {</span>
-<span class="source-line-no">565</span><span id="line-565">    final TableName tableName = TableName.valueOf(this.methodName);</span>
-<span class="source-line-no">566</span><span id="line-566">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
-<span class="source-line-no">567</span><span id="line-567">    Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">568</span><span id="line-568">    try (Admin admin = UTIL.getConnection().getAdmin()) {</span>
-<span class="source-line-no">569</span><span id="line-569">      // disable compaction</span>
-<span class="source-line-no">570</span><span id="line-570">      admin.compactionSwitch(false,</span>
-<span class="source-line-no">571</span><span id="line-571">        admin.getRegionServers().stream().map(s -&gt; s.getServerName()).collect(Collectors.toList()));</span>
-<span class="source-line-no">572</span><span id="line-572">      // create table</span>
-<span class="source-line-no">573</span><span id="line-573">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
-<span class="source-line-no">574</span><span id="line-574">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">575</span><span id="line-575">      assertEquals(3, regions.size());</span>
-<span class="source-line-no">576</span><span id="line-576">      // write some data</span>
-<span class="source-line-no">577</span><span id="line-577">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">578</span><span id="line-578">      // merge region</span>
-<span class="source-line-no">579</span><span id="line-579">      admin.mergeRegionsAsync(new byte[][] { regions.get(0).getEncodedNameAsBytes(),</span>
-<span class="source-line-no">580</span><span id="line-580">        regions.get(1).getEncodedNameAsBytes() }, false).get();</span>
-<span class="source-line-no">581</span><span id="line-581">      regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">582</span><span id="line-582">      assertEquals(2, regions.size());</span>
-<span class="source-line-no">583</span><span id="line-583">      // snapshot</span>
-<span class="source-line-no">584</span><span id="line-584">      admin.snapshot(snapshotName, tableName);</span>
-<span class="source-line-no">585</span><span id="line-585">      // verify snapshot</span>
-<span class="source-line-no">586</span><span id="line-586">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">587</span><span id="line-587">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">588</span><span id="line-588">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">589</span><span id="line-589">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">590</span><span id="line-590">      }</span>
-<span class="source-line-no">591</span><span id="line-591">      // drop table</span>
-<span class="source-line-no">592</span><span id="line-592">      admin.disableTable(tableName);</span>
-<span class="source-line-no">593</span><span id="line-593">      admin.deleteTable(tableName);</span>
-<span class="source-line-no">594</span><span id="line-594">      // verify snapshot</span>
-<span class="source-line-no">595</span><span id="line-595">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">596</span><span id="line-596">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">597</span><span id="line-597">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">598</span><span id="line-598">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">599</span><span id="line-599">      }</span>
-<span class="source-line-no">600</span><span id="line-600">    }</span>
-<span class="source-line-no">601</span><span id="line-601">  }</span>
-<span class="source-line-no">602</span><span id="line-602"></span>
-<span class="source-line-no">603</span><span id="line-603">  private void traverseAndSetFileTime(Path path, long time) throws IOException {</span>
-<span class="source-line-no">604</span><span id="line-604">    fs.setTimes(path, time, -1);</span>
-<span class="source-line-no">605</span><span id="line-605">    if (fs.isDirectory(path)) {</span>
-<span class="source-line-no">606</span><span id="line-606">      List&lt;FileStatus&gt; allPaths = Arrays.asList(fs.listStatus(path));</span>
-<span class="source-line-no">607</span><span id="line-607">      List&lt;FileStatus&gt; subDirs =</span>
-<span class="source-line-no">608</span><span id="line-608">        allPaths.stream().filter(FileStatus::isDirectory).collect(Collectors.toList());</span>
-<span class="source-line-no">609</span><span id="line-609">      List&lt;FileStatus&gt; files =</span>
-<span class="source-line-no">610</span><span id="line-610">        allPaths.stream().filter(FileStatus::isFile).collect(Collectors.toList());</span>
-<span class="source-line-no">611</span><span id="line-611">      for (FileStatus subDir : subDirs) {</span>
-<span class="source-line-no">612</span><span id="line-612">        traverseAndSetFileTime(subDir.getPath(), time);</span>
-<span class="source-line-no">613</span><span id="line-613">      }</span>
-<span class="source-line-no">614</span><span id="line-614">      for (FileStatus file : files) {</span>
-<span class="source-line-no">615</span><span id="line-615">        fs.setTimes(file.getPath(), time, -1);</span>
+<span class="source-line-no">535</span><span id="line-535">          HRegionFileSystem regionFs = HRegionFileSystem</span>
+<span class="source-line-no">536</span><span id="line-536">            .openRegionFromFileSystem(UTIL.getConfiguration(), fs, tableDir, mergedRegion, true);</span>
+<span class="source-line-no">537</span><span id="line-537">          boolean references = false;</span>
+<span class="source-line-no">538</span><span id="line-538">          Path regionDir = new Path(tableDir, mergedRegion.getEncodedName());</span>
+<span class="source-line-no">539</span><span id="line-539">          for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
+<span class="source-line-no">540</span><span id="line-540">            StoreContext storeContext = StoreContext.getBuilder()</span>
+<span class="source-line-no">541</span><span id="line-541">              .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.of(familyDir.getName()))</span>
+<span class="source-line-no">542</span><span id="line-542">              .withRegionFileSystem(regionFs).withFamilyStoreDirectoryPath(familyDir).build();</span>
+<span class="source-line-no">543</span><span id="line-543">            StoreFileTracker sft =</span>
+<span class="source-line-no">544</span><span id="line-544">              StoreFileTrackerFactory.create(UTIL.getConfiguration(), false, storeContext);</span>
+<span class="source-line-no">545</span><span id="line-545">            references = references || sft.hasReferences();</span>
+<span class="source-line-no">546</span><span id="line-546">            if (references) {</span>
+<span class="source-line-no">547</span><span id="line-547">              break;</span>
+<span class="source-line-no">548</span><span id="line-548">            }</span>
+<span class="source-line-no">549</span><span id="line-549">          }</span>
+<span class="source-line-no">550</span><span id="line-550">          return !references;</span>
+<span class="source-line-no">551</span><span id="line-551">        } catch (IOException e) {</span>
+<span class="source-line-no">552</span><span id="line-552">          LOG.warn("Failed check merged region has no reference", e);</span>
+<span class="source-line-no">553</span><span id="line-553">          return false;</span>
+<span class="source-line-no">554</span><span id="line-554">        }</span>
+<span class="source-line-no">555</span><span id="line-555">      });</span>
+<span class="source-line-no">556</span><span id="line-556">      // run catalog janitor to clean and wait for parent regions are archived</span>
+<span class="source-line-no">557</span><span id="line-557">      UTIL.getMiniHBaseCluster().getMaster().getCatalogJanitor().choreForTesting();</span>
+<span class="source-line-no">558</span><span id="line-558">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">559</span><span id="line-559">        try {</span>
+<span class="source-line-no">560</span><span id="line-560">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
+<span class="source-line-no">561</span><span id="line-561">          for (FileStatus fileStatus : fs.listStatus(tableDir)) {</span>
+<span class="source-line-no">562</span><span id="line-562">            String name = fileStatus.getPath().getName();</span>
+<span class="source-line-no">563</span><span id="line-563">            if (name.equals(region0.getEncodedName()) || name.equals(region1.getEncodedName())) {</span>
+<span class="source-line-no">564</span><span id="line-564">              return false;</span>
+<span class="source-line-no">565</span><span id="line-565">            }</span>
+<span class="source-line-no">566</span><span id="line-566">          }</span>
+<span class="source-line-no">567</span><span id="line-567">          return true;</span>
+<span class="source-line-no">568</span><span id="line-568">        } catch (IOException e) {</span>
+<span class="source-line-no">569</span><span id="line-569">          LOG.warn("Check if parent regions are archived error", e);</span>
+<span class="source-line-no">570</span><span id="line-570">          return false;</span>
+<span class="source-line-no">571</span><span id="line-571">        }</span>
+<span class="source-line-no">572</span><span id="line-572">      });</span>
+<span class="source-line-no">573</span><span id="line-573">      // set file modify time and then run cleaner</span>
+<span class="source-line-no">574</span><span id="line-574">      long time = EnvironmentEdgeManager.currentTime() - TimeToLiveHFileCleaner.DEFAULT_TTL * 1000;</span>
+<span class="source-line-no">575</span><span id="line-575">      traverseAndSetFileTime(HFileArchiveUtil.getArchivePath(conf), time);</span>
+<span class="source-line-no">576</span><span id="line-576">      UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().triggerCleanerNow().get();</span>
+<span class="source-line-no">577</span><span id="line-577">      // scan snapshot</span>
+<span class="source-line-no">578</span><span id="line-578">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">579</span><span id="line-579">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">580</span><span id="line-580">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">581</span><span id="line-581">        verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">582</span><span id="line-582">      }</span>
+<span class="source-line-no">583</span><span id="line-583">    } catch (Exception e) {</span>
+<span class="source-line-no">584</span><span id="line-584">      LOG.error("scan snapshot error", e);</span>
+<span class="source-line-no">585</span><span id="line-585">      fail("Should not throw Exception: " + e.getMessage());</span>
+<span class="source-line-no">586</span><span id="line-586">    }</span>
+<span class="source-line-no">587</span><span id="line-587">  }</span>
+<span class="source-line-no">588</span><span id="line-588"></span>
+<span class="source-line-no">589</span><span id="line-589">  @Test</span>
+<span class="source-line-no">590</span><span id="line-590">  public void testDeleteTableWithMergedRegions() throws Exception {</span>
+<span class="source-line-no">591</span><span id="line-591">    final TableName tableName = TableName.valueOf(this.methodName);</span>
+<span class="source-line-no">592</span><span id="line-592">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
+<span class="source-line-no">593</span><span id="line-593">    Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">594</span><span id="line-594">    try (Admin admin = UTIL.getConnection().getAdmin()) {</span>
+<span class="source-line-no">595</span><span id="line-595">      // disable compaction</span>
+<span class="source-line-no">596</span><span id="line-596">      admin.compactionSwitch(false,</span>
+<span class="source-line-no">597</span><span id="line-597">        admin.getRegionServers().stream().map(s -&gt; s.getServerName()).collect(Collectors.toList()));</span>
+<span class="source-line-no">598</span><span id="line-598">      // create table</span>
+<span class="source-line-no">599</span><span id="line-599">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
+<span class="source-line-no">600</span><span id="line-600">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">601</span><span id="line-601">      assertEquals(3, regions.size());</span>
+<span class="source-line-no">602</span><span id="line-602">      // write some data</span>
+<span class="source-line-no">603</span><span id="line-603">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">604</span><span id="line-604">      // merge region</span>
+<span class="source-line-no">605</span><span id="line-605">      admin.mergeRegionsAsync(new byte[][] { regions.get(0).getEncodedNameAsBytes(),</span>
+<span class="source-line-no">606</span><span id="line-606">        regions.get(1).getEncodedNameAsBytes() }, false).get();</span>
+<span class="source-line-no">607</span><span id="line-607">      regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">608</span><span id="line-608">      assertEquals(2, regions.size());</span>
+<span class="source-line-no">609</span><span id="line-609">      // snapshot</span>
+<span class="source-line-no">610</span><span id="line-610">      admin.snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">611</span><span id="line-611">      // verify snapshot</span>
+<span class="source-line-no">612</span><span id="line-612">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">613</span><span id="line-613">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">614</span><span id="line-614">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">615</span><span id="line-615">        verifyScanner(scanner, bbb, yyy);</span>
 <span class="source-line-no">616</span><span id="line-616">      }</span>
-<span class="source-line-no">617</span><span id="line-617">    }</span>
-<span class="source-line-no">618</span><span id="line-618">  }</span>
-<span class="source-line-no">619</span><span id="line-619">}</span>
+<span class="source-line-no">617</span><span id="line-617">      // drop table</span>
+<span class="source-line-no">618</span><span id="line-618">      admin.disableTable(tableName);</span>
+<span class="source-line-no">619</span><span id="line-619">      admin.deleteTable(tableName);</span>
+<span class="source-line-no">620</span><span id="line-620">      // verify snapshot</span>
+<span class="source-line-no">621</span><span id="line-621">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">622</span><span id="line-622">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">623</span><span id="line-623">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">624</span><span id="line-624">        verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">625</span><span id="line-625">      }</span>
+<span class="source-line-no">626</span><span id="line-626">    }</span>
+<span class="source-line-no">627</span><span id="line-627">  }</span>
+<span class="source-line-no">628</span><span id="line-628"></span>
+<span class="source-line-no">629</span><span id="line-629">  private void traverseAndSetFileTime(Path path, long time) throws IOException {</span>
+<span class="source-line-no">630</span><span id="line-630">    fs.setTimes(path, time, -1);</span>
+<span class="source-line-no">631</span><span id="line-631">    if (fs.isDirectory(path)) {</span>
+<span class="source-line-no">632</span><span id="line-632">      List&lt;FileStatus&gt; allPaths = Arrays.asList(fs.listStatus(path));</span>
+<span class="source-line-no">633</span><span id="line-633">      List&lt;FileStatus&gt; subDirs =</span>
+<span class="source-line-no">634</span><span id="line-634">        allPaths.stream().filter(FileStatus::isDirectory).collect(Collectors.toList());</span>
+<span class="source-line-no">635</span><span id="line-635">      List&lt;FileStatus&gt; files =</span>
+<span class="source-line-no">636</span><span id="line-636">        allPaths.stream().filter(FileStatus::isFile).collect(Collectors.toList());</span>
+<span class="source-line-no">637</span><span id="line-637">      for (FileStatus subDir : subDirs) {</span>
+<span class="source-line-no">638</span><span id="line-638">        traverseAndSetFileTime(subDir.getPath(), time);</span>
+<span class="source-line-no">639</span><span id="line-639">      }</span>
+<span class="source-line-no">640</span><span id="line-640">      for (FileStatus file : files) {</span>
+<span class="source-line-no">641</span><span id="line-641">        fs.setTimes(file.getPath(), time, -1);</span>
+<span class="source-line-no">642</span><span id="line-642">      }</span>
+<span class="source-line-no">643</span><span id="line-643">    }</span>
+<span class="source-line-no">644</span><span id="line-644">  }</span>
+<span class="source-line-no">645</span><span id="line-645">}</span>
 
 
 
diff --git a/testdevapidocs/index-all.html b/testdevapidocs/index-all.html
index a1dbe7deaec..6dd990e9fee 100644
--- a/testdevapidocs/index-all.html
+++ b/testdevapidocs/index-all.html
@@ -83331,6 +83331,8 @@ loadScripts(document, 'script');</script>
 <dd>&nbsp;</dd>
 <dt><a href="org/apache/hadoop/hbase/client/TestScannersFromClientSide.html#testScannerWithPartialResults()" class="member-name-link">testScannerWithPartialResults()</a> - Method in class org.apache.hadoop.hbase.client.<a href="org/apache/hadoop/hbase/client/TestScannersFromClientSide.html" title="class in org.apache.hadoop.hbase.client">TestScannersFromClientSide</a></dt>
 <dd>&nbsp;</dd>
+<dt><a href="org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#testScannerWithRestoredMobSnapshot()" class="member-name-link">testScannerWithRestoredMobSnapshot()</a> - Method in class org.apache.hadoop.hbase.client.<a href="org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html" title="class in org.apache.hadoop.hbase.client">TestTableSnapshotScanner</a></dt>
+<dd>&nbsp;</dd>
 <dt><a href="org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#testScannerWithRestoreScanner()" class="member-name-link">testScannerWithRestoreScanner()</a> - Method in class org.apache.hadoop.hbase.client.<a href="org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html" title="class in org.apache.hadoop.hbase.client">TestTableSnapshotScanner</a></dt>
 <dd>&nbsp;</dd>
 <dt><a href="org/apache/hadoop/hbase/rest/TestTableScan.html#testScanningUnknownColumnJson()" class="member-name-link">testScanningUnknownColumnJson()</a> - Method in class org.apache.hadoop.hbase.rest.<a href="org/apache/hadoop/hbase/rest/TestTableScan.html" title="class in org.apache.hadoop.hbase.rest">TestTableScan</a></dt>
diff --git a/testdevapidocs/member-search-index.js b/testdevapidocs/member-search-index.js
index dcebeda9cbe..8b927003c20 100644
--- a/testdevapidocs/member-search-index.js
+++ b/testdevapidocs/member-search-index.js
@@ -1 +1 @@
-memberSearchIndex = [{"p":"org.apache.hadoop.hbase.master.janitor","c":"TestMetaFixerNoCluster","l":"_ARI"},{"p":"org.apache.hadoop.hbase.io","c":"TestHalfStoreFileReader","l":"_b(String)","u":"_b(java.lang.String)"},{"p":"org.apache.hadoop.hbase.master.janitor","c":"TestMetaFixerNoCluster","l":"_BRI"},{"p":"org.apache.hadoop.hbase.backup","c":"TestSystemTableSnapshot","l":"_testBackupRestoreSystemTable()"},{"p":"org.apache.hadoop.hbase.regionserver","c":"TestBlocksScanned","l":"_testBlo [...]
\ No newline at end of file
+memberSearchIndex = [{"p":"org.apache.hadoop.hbase.master.janitor","c":"TestMetaFixerNoCluster","l":"_ARI"},{"p":"org.apache.hadoop.hbase.io","c":"TestHalfStoreFileReader","l":"_b(String)","u":"_b(java.lang.String)"},{"p":"org.apache.hadoop.hbase.master.janitor","c":"TestMetaFixerNoCluster","l":"_BRI"},{"p":"org.apache.hadoop.hbase.backup","c":"TestSystemTableSnapshot","l":"_testBackupRestoreSystemTable()"},{"p":"org.apache.hadoop.hbase.regionserver","c":"TestBlocksScanned","l":"_testBlo [...]
\ No newline at end of file
diff --git a/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html b/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
index 6786676ffe2..22e8b5a0975 100644
--- a/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
+++ b/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
@@ -82,7 +82,7 @@ loadScripts(document, 'script');</script>
 </dl>
 <hr>
 <div class="type-signature"><span class="annotations">@Tag("org.apache.hadoop.hbase.testclassification.LargeTests") @Tag("org.apache.hadoop.hbase.testclassification.ClientTests")
-</span><span class="modifiers">public class </span><span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-70">TestTableSnapshotScanner</a></span>
+</span><span class="modifiers">public class </span><span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-71">TestTableSnapshotScanner</a></span>
 <span class="extends-implements">extends <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html" title="class or interface in java.lang" class="external-link">Object</a></span></div>
 </section>
 <section class="summary">
@@ -209,29 +209,32 @@ loadScripts(document, 'script');</script>
  boolean&nbsp;shutdownCluster)</code></div>
 <div class="col-last even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
 <div class="col-first odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>void</code></div>
-<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testScannerWithRestoreScanner()" class="member-name-link">testScannerWithRestoreScanner</a>()</code></div>
+<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testScannerWithRestoredMobSnapshot()" class="member-name-link">testScannerWithRestoredMobSnapshot</a>()</code></div>
 <div class="col-last odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
 <div class="col-first even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>void</code></div>
-<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithMultiRegion()" class="member-name-link">testWithMultiRegion</a>()</code></div>
+<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testScannerWithRestoreScanner()" class="member-name-link">testScannerWithRestoreScanner</a>()</code></div>
 <div class="col-last even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
 <div class="col-first odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>void</code></div>
-<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithOfflineHBaseMultiRegion()" class="member-name-link">testWithOfflineHBaseMultiRegion</a>()</code></div>
+<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithMultiRegion()" class="member-name-link">testWithMultiRegion</a>()</code></div>
 <div class="col-last odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
 <div class="col-first even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>void</code></div>
-<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithSingleRegion()" class="member-name-link">testWithSingleRegion</a>()</code></div>
+<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithOfflineHBaseMultiRegion()" class="member-name-link">testWithOfflineHBaseMultiRegion</a>()</code></div>
 <div class="col-last even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
-<div class="col-first odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>private void</code></div>
-<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#traverseAndSetFileTime(org.apache.hadoop.fs.Path,long)" class="member-name-link">traverseAndSetFileTime</a><wbr>(org.apache.hadoop.fs.Path&nbsp;path,
- long&nbsp;time)</code></div>
+<div class="col-first odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>void</code></div>
+<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#testWithSingleRegion()" class="member-name-link">testWithSingleRegion</a>()</code></div>
 <div class="col-last odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
-<div class="col-first even-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4"><code>private static void</code></div>
-<div class="col-second even-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4"><code><a href="#verifyRow(org.apache.hadoop.hbase.client.Result)" class="member-name-link">verifyRow</a><wbr>(org.apache.hadoop.hbase.client.Result&nbsp;result)</code></div>
-<div class="col-last even-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4">&nbsp;</div>
-<div class="col-first odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>private void</code></div>
-<div class="col-second odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#verifyScanner(org.apache.hadoop.hbase.client.ResultScanner,byte%5B%5D,byte%5B%5D)" class="member-name-link">verifyScanner</a><wbr>(org.apache.hadoop.hbase.client.ResultScanner&nbsp;scanner,
+<div class="col-first even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>private void</code></div>
+<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#traverseAndSetFileTime(org.apache.hadoop.fs.Path,long)" class="member-name-link">traverseAndSetFileTime</a><wbr>(org.apache.hadoop.fs.Path&nbsp;path,
+ long&nbsp;time)</code></div>
+<div class="col-last even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
+<div class="col-first odd-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4"><code>private static void</code></div>
+<div class="col-second odd-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4"><code><a href="#verifyRow(org.apache.hadoop.hbase.client.Result)" class="member-name-link">verifyRow</a><wbr>(org.apache.hadoop.hbase.client.Result&nbsp;result)</code></div>
+<div class="col-last odd-row-color method-summary-table method-summary-table-tab1 method-summary-table-tab4">&nbsp;</div>
+<div class="col-first even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code>private void</code></div>
+<div class="col-second even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4"><code><a href="#verifyScanner(org.apache.hadoop.hbase.client.ResultScanner,byte%5B%5D,byte%5B%5D)" class="member-name-link">verifyScanner</a><wbr>(org.apache.hadoop.hbase.client.ResultScanner&nbsp;scanner,
  byte[]&nbsp;startRow,
  byte[]&nbsp;stopRow)</code></div>
-<div class="col-last odd-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
+<div class="col-last even-row-color method-summary-table method-summary-table-tab2 method-summary-table-tab4">&nbsp;</div>
 </div>
 </div>
 </div>
@@ -252,19 +255,19 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="LOG">
 <h3>LOG</h3>
-<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">org.slf4j.Logger</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-74">LOG</a></span></div>
+<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">org.slf4j.Logger</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-75">LOG</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="UTIL">
 <h3>UTIL</h3>
-<div class="member-signature"><span class="modifiers">private final</span>&nbsp;<span class="return-type"><a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-75">UTIL</a></span></div>
+<div class="member-signature"><span class="modifiers">private final</span>&nbsp;<span class="return-type"><a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-76">UTIL</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="NUM_REGION_SERVERS">
 <h3>NUM_REGION_SERVERS</h3>
-<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-76">NUM_REGION_SERVERS</a></span></div>
+<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">int</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-77">NUM_REGION_SERVERS</a></span></div>
 <dl class="notes">
 <dt>See Also:</dt>
 <dd>
@@ -278,43 +281,43 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="FAMILIES">
 <h3>FAMILIES</h3>
-<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">byte[][]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-77">FAMILIES</a></span></div>
+<div class="member-signature"><span class="modifiers">private static final</span>&nbsp;<span class="return-type">byte[][]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-78">FAMILIES</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="bbb">
 <h3>bbb</h3>
-<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">byte[]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-78">bbb</a></span></div>
+<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">byte[]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-79">bbb</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="yyy">
 <h3>yyy</h3>
-<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">byte[]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-79">yyy</a></span></div>
+<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">byte[]</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-80">yyy</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="fs">
 <h3>fs</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.FileSystem</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-81">fs</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.FileSystem</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-82">fs</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="rootDir">
 <h3>rootDir</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-82">rootDir</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.fs.Path</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-83">rootDir</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="clusterUp">
 <h3>clusterUp</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-83">clusterUp</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">boolean</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-84">clusterUp</a></span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="methodName">
 <h3>methodName</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-85">methodName</a></span></div>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a></span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-86">methodName</a></span></div>
 </section>
 </li>
 </ul>
@@ -328,7 +331,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="&lt;init&gt;()">
 <h3>TestTableSnapshotScanner</h3>
-<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-72">TestTableSnapshotScanner</a></span>()</div>
+<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-73">TestTableSnapshotScanner</a></span>()</div>
 </section>
 </li>
 </ul>
@@ -342,7 +345,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="blockUntilSplitFinished(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,int)">
 <h3>blockUntilSplitFinished</h3>
-<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-87">blockUntilSplitFinished</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
+<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-88">blockUntilSplitFinished</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
  org.apache.hadoop.hbase.TableName&nbsp;tableName,
  int&nbsp;expectedRegionSize)</span>
                                     throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
@@ -356,7 +359,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="setupCluster(org.junit.jupiter.api.TestInfo)">
 <h3>setupCluster</h3>
 <div class="member-signature"><span class="annotations">@BeforeEach
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-98">setupCluster</a></span><wbr><span class="parameters">(org.junit.jupiter.api.TestInfo&nbsp;testInfo)</span>
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-99">setupCluster</a></span><wbr><span class="parameters">(org.junit.jupiter.api.TestInfo&nbsp;testInfo)</span>
                   throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -368,7 +371,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="tearDownCluster()">
 <h3>tearDownCluster</h3>
 <div class="member-signature"><span class="annotations">@AfterEach
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-111">tearDownCluster</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-112">tearDownCluster</a></span>()
                      throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -379,13 +382,13 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="setupConf(org.apache.hadoop.conf.Configuration)">
 <h3>setupConf</h3>
-<div class="member-signature"><span class="modifiers">protected</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-118">setupConf</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf)</span></div>
+<div class="member-signature"><span class="modifiers">protected</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-119">setupConf</a></span><wbr><span class="parameters">(org.apache.hadoop.conf.Configuration&nbsp;conf)</span></div>
 </section>
 </li>
 <li>
 <section class="detail" id="createTableAndSnapshot(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,java.lang.String,int)">
 <h3>createTableAndSnapshot</h3>
-<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-123">createTableAndSnapshot</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
+<div class="member-signature"><span class="modifiers">public static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-124">createTableAndSnapshot</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
  org.apache.hadoop.hbase.TableName&nbsp;tableName,
  <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a>&nbsp;snapshotName,
  int&nbsp;numRegions)</span>
@@ -400,7 +403,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testNoDuplicateResultsWhenSplitting()">
 <h3>testNoDuplicateResultsWhenSplitting</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-157">testNoDuplicateResultsWhenSplitting</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-158">testNoDuplicateResultsWhenSplitting</a></span>()
                                          throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -412,7 +415,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScanLimit()">
 <h3>testScanLimit</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-207">testScanLimit</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-208">testScanLimit</a></span>()
                    throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -424,7 +427,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testWithSingleRegion()">
 <h3>testWithSingleRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-236">testWithSingleRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-237">testWithSingleRegion</a></span>()
                           throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -436,7 +439,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testWithMultiRegion()">
 <h3>testWithMultiRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-241">testWithMultiRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-242">testWithMultiRegion</a></span>()
                          throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -448,7 +451,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testWithOfflineHBaseMultiRegion()">
 <h3>testWithOfflineHBaseMultiRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-246">testWithOfflineHBaseMultiRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-247">testWithOfflineHBaseMultiRegion</a></span>()
                                      throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -459,7 +462,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="createTableSnapshotScannerAndGetScanMetrics(boolean,boolean,byte[])">
 <h3>createTableSnapshotScannerAndGetScanMetrics</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.hbase.client.metrics.ScanMetrics</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-251">createTableSnapshotScannerAndGetScanMetrics</a></span><wbr><span class="parameters">(boolean&nbsp;enableScanMetrics,
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.hbase.client.metrics.ScanMetrics</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-252">createTableSnapshotScannerAndGetScanMetrics</a></span><wbr><span class="parameters">(boolean&nbsp;enableScanMetrics,
  boolean&nbsp;enableScanMetricsByRegion,
  byte[]&nbsp;endKey)</span>
                                                                                                 throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
@@ -473,7 +476,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScanMetricsDisabled()">
 <h3>testScanMetricsDisabled</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-273">testScanMetricsDisabled</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-274">testScanMetricsDisabled</a></span>()
                              throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -485,7 +488,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScanMetricsWithScanMetricsByRegionDisabled()">
 <h3>testScanMetricsWithScanMetricsByRegionDisabled</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-279">testScanMetricsWithScanMetricsByRegionDisabled</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-280">testScanMetricsWithScanMetricsByRegionDisabled</a></span>()
                                                     throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -497,7 +500,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScanMetricsByRegionForSingleRegion()">
 <h3>testScanMetricsByRegionForSingleRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-293">testScanMetricsByRegionForSingleRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-294">testScanMetricsByRegionForSingleRegion</a></span>()
                                             throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -509,7 +512,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScanMetricsByRegionForMultiRegion()">
 <h3>testScanMetricsByRegionForMultiRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-313">testScanMetricsByRegionForMultiRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-314">testScanMetricsByRegionForMultiRegion</a></span>()
                                            throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -521,7 +524,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testScannerWithRestoreScanner()">
 <h3>testScannerWithRestoreScanner</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-329">testScannerWithRestoreScanner</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-330">testScannerWithRestoreScanner</a></span>()
                                    throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -530,9 +533,21 @@ loadScripts(document, 'script');</script>
 </section>
 </li>
 <li>
+<section class="detail" id="testScannerWithRestoredMobSnapshot()">
+<h3>testScannerWithRestoredMobSnapshot</h3>
+<div class="member-signature"><span class="annotations">@Test
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-374">testScannerWithRestoredMobSnapshot</a></span>()
+                                        throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
+<dl class="notes">
+<dt>Throws:</dt>
+<dd><code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></code></dd>
+</dl>
+</section>
+</li>
+<li>
 <section class="detail" id="testScanner(org.apache.hadoop.hbase.HBaseTestingUtil,java.lang.String,int,boolean)">
 <h3>testScanner</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-373">testScanner</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-399">testScanner</a></span><wbr><span class="parameters">(<a href="../HBaseTestingUtil.html" title="class in org.apache.hadoop.hbase">HBaseTestingUtil</a>&nbsp;util,
  <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html" title="class or interface in java.lang" class="external-link">String</a>&nbsp;snapshotName,
  int&nbsp;numRegions,
  boolean&nbsp;shutdownCluster)</span>
@@ -546,7 +561,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="verifyScanner(org.apache.hadoop.hbase.client.ResultScanner,byte[],byte[])">
 <h3>verifyScanner</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-400">verifyScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.client.ResultScanner&nbsp;scanner,
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-426">verifyScanner</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.client.ResultScanner&nbsp;scanner,
  byte[]&nbsp;startRow,
  byte[]&nbsp;stopRow)</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>,
@@ -561,7 +576,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="verifyRow(org.apache.hadoop.hbase.client.Result)">
 <h3>verifyRow</h3>
-<div class="member-signature"><span class="modifiers">private static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-419">verifyRow</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.client.Result&nbsp;result)</span>
+<div class="member-signature"><span class="modifiers">private static</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-445">verifyRow</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.client.Result&nbsp;result)</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>
@@ -573,7 +588,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testMergeRegion()">
 <h3>testMergeRegion</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-437">testMergeRegion</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-463">testMergeRegion</a></span>()
                      throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -585,7 +600,7 @@ loadScripts(document, 'script');</script>
 <section class="detail" id="testDeleteTableWithMergedRegions()">
 <h3>testDeleteTableWithMergedRegions</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-563">testDeleteTableWithMergedRegions</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-589">testDeleteTableWithMergedRegions</a></span>()
                                       throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
@@ -596,7 +611,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="traverseAndSetFileTime(org.apache.hadoop.fs.Path,long)">
 <h3>traverseAndSetFileTime</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-603">traverseAndSetFileTime</a></span><wbr><span class="parameters">(org.apache.hadoop.fs.Path&nbsp;path,
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html#line-629">traverseAndSetFileTime</a></span><wbr><span class="parameters">(org.apache.hadoop.fs.Path&nbsp;path,
  long&nbsp;time)</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">
diff --git a/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScannerWithSFT.html b/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScannerWithSFT.html
index 899fb830aa1..910a680cd5d 100644
--- a/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScannerWithSFT.html
+++ b/testdevapidocs/org/apache/hadoop/hbase/client/TestTableSnapshotScannerWithSFT.html
@@ -126,7 +126,7 @@ loadScripts(document, 'script');</script>
 </div>
 <div class="inherited-list">
 <h3 id="methods-inherited-from-class-org.apache.hadoop.hbase.client.TestTableSnapshotScanner">Methods inherited from class&nbsp;org.apache.hadoop.hbase.client.<a href="TestTableSnapshotScanner.html" title="class in org.apache.hadoop.hbase.client">TestTableSnapshotScanner</a></h3>
-<code><a href="TestTableSnapshotScanner.html#blockUntilSplitFinished(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,int)">blockUntilSplitFinished</a>, <a href="TestTableSnapshotScanner.html#createTableAndSnapshot(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,java.lang.String,int)">createTableAndSnapshot</a>, <a href="TestTableSnapshotScanner.html#setupCluster(org.junit.jupiter.api.TestInfo)">setupCluster</a>, <a href="TestTableSnap [...]
+<code><a href="TestTableSnapshotScanner.html#blockUntilSplitFinished(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,int)">blockUntilSplitFinished</a>, <a href="TestTableSnapshotScanner.html#createTableAndSnapshot(org.apache.hadoop.hbase.HBaseTestingUtil,org.apache.hadoop.hbase.TableName,java.lang.String,int)">createTableAndSnapshot</a>, <a href="TestTableSnapshotScanner.html#setupCluster(org.junit.jupiter.api.TestInfo)">setupCluster</a>, <a href="TestTableSnap [...]
 <div class="inherited-list">
 <h3 id="methods-inherited-from-class-java.lang.Object">Methods inherited from class&nbsp;java.lang.<a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html" title="class or interface in java.lang" class="external-link">Object</a></h3>
 <code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#clone()" title="class or interface in java.lang" class="external-link">clone</a>, <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#equals(java.lang.Object)" title="class or interface in java.lang" class="external-link">equals</a>, <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#finalize()" title="class or  [...]
diff --git a/testdevapidocs/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html b/testdevapidocs/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
index 7fad1d7f82f..200713ce58b 100644
--- a/testdevapidocs/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
+++ b/testdevapidocs/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
@@ -272,7 +272,7 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="getSCPForServer(org.apache.hadoop.hbase.ServerName)">
 <h3>getSCPForServer</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.hbase.master.procedure.ServerCrashProcedure</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-138">getSCPForServer</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.ServerName&nbsp;serverName)</span>
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.apache.hadoop.hbase.master.procedure.ServerCrashProcedure</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-143">getSCPForServer</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.ServerName&nbsp;serverName)</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>
@@ -283,14 +283,14 @@ loadScripts(document, 'script');</script>
 <li>
 <section class="detail" id="subProcOf(org.apache.hadoop.hbase.procedure2.Procedure)">
 <h3>subProcOf</h3>
-<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.hamcrest.Matcher&lt;org.apache.hadoop.hbase.procedure2.Procedure&lt;org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv&gt;&gt;</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-144">subProcOf</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.procedure2.Procedure&lt;org.a [...]
+<div class="member-signature"><span class="modifiers">private</span>&nbsp;<span class="return-type">org.hamcrest.Matcher&lt;org.apache.hadoop.hbase.procedure2.Procedure&lt;org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv&gt;&gt;</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-149">subProcOf</a></span><wbr><span class="parameters">(org.apache.hadoop.hbase.procedure2.Procedure&lt;org.a [...]
 </section>
 </li>
 <li>
 <section class="detail" id="testFailAndRollback()">
 <h3>testFailAndRollback</h3>
 <div class="member-signature"><span class="annotations">@Test
-</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-163">testFailAndRollback</a></span>()
+</span><span class="modifiers">public</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name"><a href="../../../../../../src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html#line-168">testFailAndRollback</a></span>()
                          throws <span class="exceptions"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Exception.html" title="class or interface in java.lang" class="external-link">Exception</a></span></div>
 <dl class="notes">
 <dt>Throws:</dt>
diff --git a/testdevapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html b/testdevapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
index 9ffff1f2453..fbcf5419bbf 100644
--- a/testdevapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
+++ b/testdevapidocs/src-html/org/apache/hadoop/hbase/client/TestTableSnapshotScanner.html
@@ -62,574 +62,600 @@
 <span class="source-line-no">049</span><span id="line-49">import org.apache.hadoop.hbase.regionserver.StoreContext;</span>
 <span class="source-line-no">050</span><span id="line-50">import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker;</span>
 <span class="source-line-no">051</span><span id="line-51">import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;</span>
-<span class="source-line-no">052</span><span id="line-52">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
-<span class="source-line-no">053</span><span id="line-53">import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;</span>
-<span class="source-line-no">054</span><span id="line-54">import org.apache.hadoop.hbase.testclassification.ClientTests;</span>
-<span class="source-line-no">055</span><span id="line-55">import org.apache.hadoop.hbase.testclassification.LargeTests;</span>
-<span class="source-line-no">056</span><span id="line-56">import org.apache.hadoop.hbase.util.Bytes;</span>
-<span class="source-line-no">057</span><span id="line-57">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
-<span class="source-line-no">058</span><span id="line-58">import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;</span>
-<span class="source-line-no">059</span><span id="line-59">import org.apache.hadoop.hbase.util.FSUtils;</span>
-<span class="source-line-no">060</span><span id="line-60">import org.apache.hadoop.hbase.util.HFileArchiveUtil;</span>
-<span class="source-line-no">061</span><span id="line-61">import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;</span>
-<span class="source-line-no">062</span><span id="line-62">import org.junit.jupiter.api.AfterEach;</span>
-<span class="source-line-no">063</span><span id="line-63">import org.junit.jupiter.api.BeforeEach;</span>
-<span class="source-line-no">064</span><span id="line-64">import org.junit.jupiter.api.Tag;</span>
-<span class="source-line-no">065</span><span id="line-65">import org.junit.jupiter.api.Test;</span>
-<span class="source-line-no">066</span><span id="line-66">import org.junit.jupiter.api.TestInfo;</span>
-<span class="source-line-no">067</span><span id="line-67">import org.slf4j.Logger;</span>
-<span class="source-line-no">068</span><span id="line-68">import org.slf4j.LoggerFactory;</span>
-<span class="source-line-no">069</span><span id="line-69"></span>
-<span class="source-line-no">070</span><span id="line-70">@Tag(LargeTests.TAG)</span>
-<span class="source-line-no">071</span><span id="line-71">@Tag(ClientTests.TAG)</span>
-<span class="source-line-no">072</span><span id="line-72">public class TestTableSnapshotScanner {</span>
-<span class="source-line-no">073</span><span id="line-73"></span>
-<span class="source-line-no">074</span><span id="line-74">  private static final Logger LOG = LoggerFactory.getLogger(TestTableSnapshotScanner.class);</span>
-<span class="source-line-no">075</span><span id="line-75">  private final HBaseTestingUtil UTIL = new HBaseTestingUtil();</span>
-<span class="source-line-no">076</span><span id="line-76">  private static final int NUM_REGION_SERVERS = 2;</span>
-<span class="source-line-no">077</span><span id="line-77">  private static final byte[][] FAMILIES = { Bytes.toBytes("f1"), Bytes.toBytes("f2") };</span>
-<span class="source-line-no">078</span><span id="line-78">  public static byte[] bbb = Bytes.toBytes("bbb");</span>
-<span class="source-line-no">079</span><span id="line-79">  public static byte[] yyy = Bytes.toBytes("yyy");</span>
-<span class="source-line-no">080</span><span id="line-80"></span>
-<span class="source-line-no">081</span><span id="line-81">  private FileSystem fs;</span>
-<span class="source-line-no">082</span><span id="line-82">  private Path rootDir;</span>
-<span class="source-line-no">083</span><span id="line-83">  private boolean clusterUp;</span>
-<span class="source-line-no">084</span><span id="line-84"></span>
-<span class="source-line-no">085</span><span id="line-85">  private String methodName;</span>
-<span class="source-line-no">086</span><span id="line-86"></span>
-<span class="source-line-no">087</span><span id="line-87">  public static void blockUntilSplitFinished(HBaseTestingUtil util, TableName tableName,</span>
-<span class="source-line-no">088</span><span id="line-88">    int expectedRegionSize) throws Exception {</span>
-<span class="source-line-no">089</span><span id="line-89">    for (int i = 0; i &lt; 100; i++) {</span>
-<span class="source-line-no">090</span><span id="line-90">      List&lt;RegionInfo&gt; hRegionInfoList = util.getAdmin().getRegions(tableName);</span>
-<span class="source-line-no">091</span><span id="line-91">      if (hRegionInfoList.size() &gt;= expectedRegionSize) {</span>
-<span class="source-line-no">092</span><span id="line-92">        break;</span>
-<span class="source-line-no">093</span><span id="line-93">      }</span>
-<span class="source-line-no">094</span><span id="line-94">      Thread.sleep(1000);</span>
-<span class="source-line-no">095</span><span id="line-95">    }</span>
-<span class="source-line-no">096</span><span id="line-96">  }</span>
-<span class="source-line-no">097</span><span id="line-97"></span>
-<span class="source-line-no">098</span><span id="line-98">  @BeforeEach</span>
-<span class="source-line-no">099</span><span id="line-99">  public void setupCluster(TestInfo testInfo) throws Exception {</span>
-<span class="source-line-no">100</span><span id="line-100">    methodName = testInfo.getTestMethod().get().getName();</span>
-<span class="source-line-no">101</span><span id="line-101">    setupConf(UTIL.getConfiguration());</span>
-<span class="source-line-no">102</span><span id="line-102">    StartTestingClusterOption option =</span>
-<span class="source-line-no">103</span><span id="line-103">      StartTestingClusterOption.builder().numRegionServers(NUM_REGION_SERVERS)</span>
-<span class="source-line-no">104</span><span id="line-104">        .numDataNodes(NUM_REGION_SERVERS).createRootDir(true).build();</span>
-<span class="source-line-no">105</span><span id="line-105">    UTIL.startMiniCluster(option);</span>
-<span class="source-line-no">106</span><span id="line-106">    clusterUp = true;</span>
-<span class="source-line-no">107</span><span id="line-107">    rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
-<span class="source-line-no">108</span><span id="line-108">    fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
-<span class="source-line-no">109</span><span id="line-109">  }</span>
-<span class="source-line-no">110</span><span id="line-110"></span>
-<span class="source-line-no">111</span><span id="line-111">  @AfterEach</span>
-<span class="source-line-no">112</span><span id="line-112">  public void tearDownCluster() throws Exception {</span>
-<span class="source-line-no">113</span><span id="line-113">    if (clusterUp) {</span>
-<span class="source-line-no">114</span><span id="line-114">      UTIL.shutdownMiniCluster();</span>
-<span class="source-line-no">115</span><span id="line-115">    }</span>
-<span class="source-line-no">116</span><span id="line-116">  }</span>
-<span class="source-line-no">117</span><span id="line-117"></span>
-<span class="source-line-no">118</span><span id="line-118">  protected void setupConf(Configuration conf) {</span>
-<span class="source-line-no">119</span><span id="line-119">    // Enable snapshot</span>
-<span class="source-line-no">120</span><span id="line-120">    conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);</span>
-<span class="source-line-no">121</span><span id="line-121">  }</span>
-<span class="source-line-no">122</span><span id="line-122"></span>
-<span class="source-line-no">123</span><span id="line-123">  public static void createTableAndSnapshot(HBaseTestingUtil util, TableName tableName,</span>
-<span class="source-line-no">124</span><span id="line-124">    String snapshotName, int numRegions) throws Exception {</span>
-<span class="source-line-no">125</span><span id="line-125">    try {</span>
-<span class="source-line-no">126</span><span id="line-126">      util.deleteTable(tableName);</span>
-<span class="source-line-no">127</span><span id="line-127">    } catch (Exception ex) {</span>
-<span class="source-line-no">128</span><span id="line-128">      // ignore</span>
-<span class="source-line-no">129</span><span id="line-129">    }</span>
-<span class="source-line-no">130</span><span id="line-130"></span>
-<span class="source-line-no">131</span><span id="line-131">    if (numRegions &gt; 1) {</span>
-<span class="source-line-no">132</span><span id="line-132">      util.createTable(tableName, FAMILIES, 1, bbb, yyy, numRegions);</span>
-<span class="source-line-no">133</span><span id="line-133">    } else {</span>
-<span class="source-line-no">134</span><span id="line-134">      util.createTable(tableName, FAMILIES);</span>
-<span class="source-line-no">135</span><span id="line-135">    }</span>
-<span class="source-line-no">136</span><span id="line-136">    Admin admin = util.getAdmin();</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">    // put some stuff in the table</span>
-<span class="source-line-no">139</span><span id="line-139">    Table table = util.getConnection().getTable(tableName);</span>
-<span class="source-line-no">140</span><span id="line-140">    util.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">141</span><span id="line-141"></span>
-<span class="source-line-no">142</span><span id="line-142">    Path rootDir = CommonFSUtils.getRootDir(util.getConfiguration());</span>
-<span class="source-line-no">143</span><span id="line-143">    FileSystem fs = rootDir.getFileSystem(util.getConfiguration());</span>
-<span class="source-line-no">144</span><span id="line-144"></span>
-<span class="source-line-no">145</span><span id="line-145">    SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES), null,</span>
-<span class="source-line-no">146</span><span id="line-146">      snapshotName, rootDir, fs, true);</span>
-<span class="source-line-no">147</span><span id="line-147"></span>
-<span class="source-line-no">148</span><span id="line-148">    // load different values</span>
-<span class="source-line-no">149</span><span id="line-149">    byte[] value = Bytes.toBytes("after_snapshot_value");</span>
-<span class="source-line-no">150</span><span id="line-150">    util.loadTable(table, FAMILIES, value);</span>
-<span class="source-line-no">151</span><span id="line-151"></span>
-<span class="source-line-no">152</span><span id="line-152">    // cause flush to create new files in the region</span>
-<span class="source-line-no">153</span><span id="line-153">    admin.flush(tableName);</span>
-<span class="source-line-no">154</span><span id="line-154">    table.close();</span>
-<span class="source-line-no">155</span><span id="line-155">  }</span>
-<span class="source-line-no">156</span><span id="line-156"></span>
-<span class="source-line-no">157</span><span id="line-157">  @Test</span>
-<span class="source-line-no">158</span><span id="line-158">  public void testNoDuplicateResultsWhenSplitting() throws Exception {</span>
-<span class="source-line-no">159</span><span id="line-159">    TableName tableName = TableName.valueOf("testNoDuplicateResultsWhenSplitting");</span>
-<span class="source-line-no">160</span><span id="line-160">    String snapshotName = "testSnapshotBug";</span>
-<span class="source-line-no">161</span><span id="line-161">    try {</span>
-<span class="source-line-no">162</span><span id="line-162">      if (UTIL.getAdmin().tableExists(tableName)) {</span>
-<span class="source-line-no">163</span><span id="line-163">        UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">164</span><span id="line-164">      }</span>
-<span class="source-line-no">165</span><span id="line-165"></span>
-<span class="source-line-no">166</span><span id="line-166">      UTIL.createTable(tableName, FAMILIES);</span>
-<span class="source-line-no">167</span><span id="line-167">      Admin admin = UTIL.getAdmin();</span>
-<span class="source-line-no">168</span><span id="line-168"></span>
-<span class="source-line-no">169</span><span id="line-169">      // put some stuff in the table</span>
-<span class="source-line-no">170</span><span id="line-170">      Table table = UTIL.getConnection().getTable(tableName);</span>
-<span class="source-line-no">171</span><span id="line-171">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">172</span><span id="line-172"></span>
-<span class="source-line-no">173</span><span id="line-173">      // split to 2 regions</span>
-<span class="source-line-no">174</span><span id="line-174">      admin.split(tableName, Bytes.toBytes("eee"));</span>
-<span class="source-line-no">175</span><span id="line-175">      blockUntilSplitFinished(UTIL, tableName, 2);</span>
-<span class="source-line-no">176</span><span id="line-176"></span>
-<span class="source-line-no">177</span><span id="line-177">      Path rootDir = CommonFSUtils.getRootDir(UTIL.getConfiguration());</span>
-<span class="source-line-no">178</span><span id="line-178">      FileSystem fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
-<span class="source-line-no">179</span><span id="line-179"></span>
-<span class="source-line-no">180</span><span id="line-180">      SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES),</span>
-<span class="source-line-no">181</span><span id="line-181">        null, snapshotName, rootDir, fs, true);</span>
-<span class="source-line-no">182</span><span id="line-182"></span>
-<span class="source-line-no">183</span><span id="line-183">      // load different values</span>
-<span class="source-line-no">184</span><span id="line-184">      byte[] value = Bytes.toBytes("after_snapshot_value");</span>
-<span class="source-line-no">185</span><span id="line-185">      UTIL.loadTable(table, FAMILIES, value);</span>
-<span class="source-line-no">186</span><span id="line-186"></span>
-<span class="source-line-no">187</span><span id="line-187">      // cause flush to create new files in the region</span>
-<span class="source-line-no">188</span><span id="line-188">      admin.flush(tableName);</span>
-<span class="source-line-no">189</span><span id="line-189">      table.close();</span>
-<span class="source-line-no">190</span><span id="line-190"></span>
-<span class="source-line-no">191</span><span id="line-191">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">192</span><span id="line-192">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">193</span><span id="line-193"></span>
-<span class="source-line-no">194</span><span id="line-194">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">195</span><span id="line-195">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">196</span><span id="line-196"></span>
-<span class="source-line-no">197</span><span id="line-197">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">198</span><span id="line-198">      scanner.close();</span>
-<span class="source-line-no">199</span><span id="line-199">    } catch (Exception e) {</span>
-<span class="source-line-no">200</span><span id="line-200">      e.printStackTrace();</span>
-<span class="source-line-no">201</span><span id="line-201">    } finally {</span>
-<span class="source-line-no">202</span><span id="line-202">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">203</span><span id="line-203">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">204</span><span id="line-204">    }</span>
-<span class="source-line-no">205</span><span id="line-205">  }</span>
-<span class="source-line-no">206</span><span id="line-206"></span>
-<span class="source-line-no">207</span><span id="line-207">  @Test</span>
-<span class="source-line-no">208</span><span id="line-208">  public void testScanLimit() throws Exception {</span>
-<span class="source-line-no">209</span><span id="line-209">    final TableName tableName = TableName.valueOf(methodName);</span>
-<span class="source-line-no">210</span><span id="line-210">    final String snapshotName = tableName + "Snapshot";</span>
-<span class="source-line-no">211</span><span id="line-211">    TableSnapshotScanner scanner = null;</span>
-<span class="source-line-no">212</span><span id="line-212">    try {</span>
-<span class="source-line-no">213</span><span id="line-213">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">214</span><span id="line-214">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">215</span><span id="line-215">      Scan scan = new Scan().withStartRow(bbb).setLimit(100); // limit the scan</span>
-<span class="source-line-no">216</span><span id="line-216"></span>
-<span class="source-line-no">217</span><span id="line-217">      scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">218</span><span id="line-218">      int count = 0;</span>
-<span class="source-line-no">219</span><span id="line-219">      while (true) {</span>
-<span class="source-line-no">220</span><span id="line-220">        Result result = scanner.next();</span>
-<span class="source-line-no">221</span><span id="line-221">        if (result == null) {</span>
-<span class="source-line-no">222</span><span id="line-222">          break;</span>
-<span class="source-line-no">223</span><span id="line-223">        }</span>
-<span class="source-line-no">224</span><span id="line-224">        count++;</span>
-<span class="source-line-no">225</span><span id="line-225">      }</span>
-<span class="source-line-no">226</span><span id="line-226">      assertEquals(100, count);</span>
-<span class="source-line-no">227</span><span id="line-227">    } finally {</span>
-<span class="source-line-no">228</span><span id="line-228">      if (scanner != null) {</span>
-<span class="source-line-no">229</span><span id="line-229">        scanner.close();</span>
-<span class="source-line-no">230</span><span id="line-230">      }</span>
-<span class="source-line-no">231</span><span id="line-231">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">232</span><span id="line-232">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">233</span><span id="line-233">    }</span>
-<span class="source-line-no">234</span><span id="line-234">  }</span>
-<span class="source-line-no">235</span><span id="line-235"></span>
-<span class="source-line-no">236</span><span id="line-236">  @Test</span>
-<span class="source-line-no">237</span><span id="line-237">  public void testWithSingleRegion() throws Exception {</span>
-<span class="source-line-no">238</span><span id="line-238">    testScanner(UTIL, "testWithSingleRegion", 1, false);</span>
-<span class="source-line-no">239</span><span id="line-239">  }</span>
-<span class="source-line-no">240</span><span id="line-240"></span>
-<span class="source-line-no">241</span><span id="line-241">  @Test</span>
-<span class="source-line-no">242</span><span id="line-242">  public void testWithMultiRegion() throws Exception {</span>
-<span class="source-line-no">243</span><span id="line-243">    testScanner(UTIL, "testWithMultiRegion", 10, false);</span>
-<span class="source-line-no">244</span><span id="line-244">  }</span>
-<span class="source-line-no">245</span><span id="line-245"></span>
-<span class="source-line-no">246</span><span id="line-246">  @Test</span>
-<span class="source-line-no">247</span><span id="line-247">  public void testWithOfflineHBaseMultiRegion() throws Exception {</span>
-<span class="source-line-no">248</span><span id="line-248">    testScanner(UTIL, "testWithMultiRegion", 20, true);</span>
-<span class="source-line-no">249</span><span id="line-249">  }</span>
-<span class="source-line-no">250</span><span id="line-250"></span>
-<span class="source-line-no">251</span><span id="line-251">  private ScanMetrics createTableSnapshotScannerAndGetScanMetrics(boolean enableScanMetrics,</span>
-<span class="source-line-no">252</span><span id="line-252">    boolean enableScanMetricsByRegion, byte[] endKey) throws Exception {</span>
-<span class="source-line-no">253</span><span id="line-253">    TableName tableName = TableName.valueOf(methodName + "_TABLE");</span>
-<span class="source-line-no">254</span><span id="line-254">    String snapshotName = methodName + "_SNAPSHOT";</span>
-<span class="source-line-no">255</span><span id="line-255">    try {</span>
-<span class="source-line-no">256</span><span id="line-256">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">257</span><span id="line-257">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">258</span><span id="line-258">      Scan scan = new Scan().withStartRow(bbb).withStopRow(endKey);</span>
-<span class="source-line-no">259</span><span id="line-259">      scan.setScanMetricsEnabled(enableScanMetrics);</span>
-<span class="source-line-no">260</span><span id="line-260">      scan.setEnableScanMetricsByRegion(enableScanMetricsByRegion);</span>
-<span class="source-line-no">261</span><span id="line-261">      Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">262</span><span id="line-262"></span>
-<span class="source-line-no">263</span><span id="line-263">      TableSnapshotScanner snapshotScanner =</span>
-<span class="source-line-no">264</span><span id="line-264">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">265</span><span id="line-265">      verifyScanner(snapshotScanner, bbb, endKey);</span>
-<span class="source-line-no">266</span><span id="line-266">      return snapshotScanner.getScanMetrics();</span>
-<span class="source-line-no">267</span><span id="line-267">    } finally {</span>
-<span class="source-line-no">268</span><span id="line-268">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">269</span><span id="line-269">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">270</span><span id="line-270">    }</span>
-<span class="source-line-no">271</span><span id="line-271">  }</span>
-<span class="source-line-no">272</span><span id="line-272"></span>
-<span class="source-line-no">273</span><span id="line-273">  @Test</span>
-<span class="source-line-no">274</span><span id="line-274">  public void testScanMetricsDisabled() throws Exception {</span>
-<span class="source-line-no">275</span><span id="line-275">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(false, false, yyy);</span>
-<span class="source-line-no">276</span><span id="line-276">    assertNull(scanMetrics);</span>
-<span class="source-line-no">277</span><span id="line-277">  }</span>
-<span class="source-line-no">278</span><span id="line-278"></span>
-<span class="source-line-no">279</span><span id="line-279">  @Test</span>
-<span class="source-line-no">280</span><span id="line-280">  public void testScanMetricsWithScanMetricsByRegionDisabled() throws Exception {</span>
-<span class="source-line-no">281</span><span id="line-281">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, false, yyy);</span>
-<span class="source-line-no">282</span><span id="line-282">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">283</span><span id="line-283">    int rowsScanned = 0;</span>
-<span class="source-line-no">284</span><span id="line-284">    for (byte[] row : HBaseTestingUtil.ROWS) {</span>
-<span class="source-line-no">285</span><span id="line-285">      if (Bytes.compareTo(row, bbb) &gt;= 0 &amp;&amp; Bytes.compareTo(row, yyy) &lt; 0) {</span>
-<span class="source-line-no">286</span><span id="line-286">        rowsScanned++;</span>
-<span class="source-line-no">287</span><span id="line-287">      }</span>
-<span class="source-line-no">288</span><span id="line-288">    }</span>
-<span class="source-line-no">289</span><span id="line-289">    Map&lt;String, Long&gt; metricsMap = scanMetrics.getMetricsMap();</span>
-<span class="source-line-no">290</span><span id="line-290">    assertEquals(rowsScanned, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
-<span class="source-line-no">291</span><span id="line-291">  }</span>
-<span class="source-line-no">292</span><span id="line-292"></span>
-<span class="source-line-no">293</span><span id="line-293">  @Test</span>
-<span class="source-line-no">294</span><span id="line-294">  public void testScanMetricsByRegionForSingleRegion() throws Exception {</span>
-<span class="source-line-no">295</span><span id="line-295">    // Scan single row with row key bbb</span>
-<span class="source-line-no">296</span><span id="line-296">    byte[] bbc = Bytes.toBytes("bbc");</span>
-<span class="source-line-no">297</span><span id="line-297">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, bbc);</span>
-<span class="source-line-no">298</span><span id="line-298">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">299</span><span id="line-299">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
-<span class="source-line-no">300</span><span id="line-300">      scanMetrics.collectMetricsByRegion();</span>
-<span class="source-line-no">301</span><span id="line-301">    assertEquals(1, scanMetricsByRegion.size());</span>
-<span class="source-line-no">302</span><span id="line-302">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
-<span class="source-line-no">303</span><span id="line-303">      .entrySet()) {</span>
-<span class="source-line-no">304</span><span id="line-304">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
-<span class="source-line-no">305</span><span id="line-305">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
-<span class="source-line-no">306</span><span id="line-306">      assertNull(scanMetricsRegionInfo.getServerName());</span>
-<span class="source-line-no">307</span><span id="line-307">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
-<span class="source-line-no">308</span><span id="line-308">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
-<span class="source-line-no">309</span><span id="line-309">      assertEquals(1, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
-<span class="source-line-no">310</span><span id="line-310">    }</span>
-<span class="source-line-no">311</span><span id="line-311">  }</span>
-<span class="source-line-no">312</span><span id="line-312"></span>
-<span class="source-line-no">313</span><span id="line-313">  @Test</span>
-<span class="source-line-no">314</span><span id="line-314">  public void testScanMetricsByRegionForMultiRegion() throws Exception {</span>
-<span class="source-line-no">315</span><span id="line-315">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, yyy);</span>
-<span class="source-line-no">316</span><span id="line-316">    assertNotNull(scanMetrics);</span>
-<span class="source-line-no">317</span><span id="line-317">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
-<span class="source-line-no">318</span><span id="line-318">      scanMetrics.collectMetricsByRegion();</span>
-<span class="source-line-no">319</span><span id="line-319">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
-<span class="source-line-no">320</span><span id="line-320">      .entrySet()) {</span>
-<span class="source-line-no">321</span><span id="line-321">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
-<span class="source-line-no">322</span><span id="line-322">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
-<span class="source-line-no">323</span><span id="line-323">      assertNull(scanMetricsRegionInfo.getServerName());</span>
-<span class="source-line-no">324</span><span id="line-324">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
-<span class="source-line-no">325</span><span id="line-325">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
-<span class="source-line-no">326</span><span id="line-326">    }</span>
-<span class="source-line-no">327</span><span id="line-327">  }</span>
-<span class="source-line-no">328</span><span id="line-328"></span>
-<span class="source-line-no">329</span><span id="line-329">  @Test</span>
-<span class="source-line-no">330</span><span id="line-330">  public void testScannerWithRestoreScanner() throws Exception {</span>
-<span class="source-line-no">331</span><span id="line-331">    TableName tableName = TableName.valueOf("testScanner");</span>
-<span class="source-line-no">332</span><span id="line-332">    String snapshotName = "testScannerWithRestoreScanner";</span>
-<span class="source-line-no">333</span><span id="line-333">    try {</span>
-<span class="source-line-no">334</span><span id="line-334">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
-<span class="source-line-no">335</span><span id="line-335">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">336</span><span id="line-336">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">337</span><span id="line-337"></span>
-<span class="source-line-no">338</span><span id="line-338">      Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">339</span><span id="line-339">      Path rootDir = CommonFSUtils.getRootDir(conf);</span>
-<span class="source-line-no">340</span><span id="line-340"></span>
-<span class="source-line-no">341</span><span id="line-341">      TableSnapshotScanner scanner0 =</span>
-<span class="source-line-no">342</span><span id="line-342">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">343</span><span id="line-343">      verifyScanner(scanner0, bbb, yyy);</span>
-<span class="source-line-no">344</span><span id="line-344">      scanner0.close();</span>
-<span class="source-line-no">345</span><span id="line-345"></span>
-<span class="source-line-no">346</span><span id="line-346">      // restore snapshot.</span>
-<span class="source-line-no">347</span><span id="line-347">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">348</span><span id="line-348"></span>
-<span class="source-line-no">349</span><span id="line-349">      // scan the snapshot without restoring snapshot</span>
-<span class="source-line-no">350</span><span id="line-350">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">351</span><span id="line-351">        new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">352</span><span id="line-352">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">353</span><span id="line-353">      scanner.close();</span>
-<span class="source-line-no">354</span><span id="line-354"></span>
-<span class="source-line-no">355</span><span id="line-355">      // check whether the snapshot has been deleted by the close of scanner.</span>
-<span class="source-line-no">356</span><span id="line-356">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">357</span><span id="line-357">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">358</span><span id="line-358">      scanner.close();</span>
-<span class="source-line-no">359</span><span id="line-359"></span>
-<span class="source-line-no">360</span><span id="line-360">      // restore snapshot again.</span>
-<span class="source-line-no">361</span><span id="line-361">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
-<span class="source-line-no">362</span><span id="line-362"></span>
-<span class="source-line-no">363</span><span id="line-363">      // check whether the snapshot has been deleted by the close of scanner.</span>
-<span class="source-line-no">364</span><span id="line-364">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
-<span class="source-line-no">365</span><span id="line-365">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">366</span><span id="line-366">      scanner.close();</span>
-<span class="source-line-no">367</span><span id="line-367">    } finally {</span>
-<span class="source-line-no">368</span><span id="line-368">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">369</span><span id="line-369">      UTIL.deleteTable(tableName);</span>
-<span class="source-line-no">370</span><span id="line-370">    }</span>
-<span class="source-line-no">371</span><span id="line-371">  }</span>
-<span class="source-line-no">372</span><span id="line-372"></span>
-<span class="source-line-no">373</span><span id="line-373">  private void testScanner(HBaseTestingUtil util, String snapshotName, int numRegions,</span>
-<span class="source-line-no">374</span><span id="line-374">    boolean shutdownCluster) throws Exception {</span>
-<span class="source-line-no">375</span><span id="line-375">    TableName tableName = TableName.valueOf("testScanner");</span>
-<span class="source-line-no">376</span><span id="line-376">    try {</span>
-<span class="source-line-no">377</span><span id="line-377">      createTableAndSnapshot(util, tableName, snapshotName, numRegions);</span>
-<span class="source-line-no">378</span><span id="line-378"></span>
-<span class="source-line-no">379</span><span id="line-379">      if (shutdownCluster) {</span>
-<span class="source-line-no">380</span><span id="line-380">        util.shutdownMiniHBaseCluster();</span>
-<span class="source-line-no">381</span><span id="line-381">        clusterUp = false;</span>
-<span class="source-line-no">382</span><span id="line-382">      }</span>
-<span class="source-line-no">383</span><span id="line-383"></span>
-<span class="source-line-no">384</span><span id="line-384">      Path restoreDir = util.getDataTestDirOnTestFS(snapshotName);</span>
-<span class="source-line-no">385</span><span id="line-385">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
-<span class="source-line-no">386</span><span id="line-386"></span>
-<span class="source-line-no">387</span><span id="line-387">      TableSnapshotScanner scanner =</span>
-<span class="source-line-no">388</span><span id="line-388">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
-<span class="source-line-no">389</span><span id="line-389"></span>
-<span class="source-line-no">390</span><span id="line-390">      verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">391</span><span id="line-391">      scanner.close();</span>
+<span class="source-line-no">052</span><span id="line-52">import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils;</span>
+<span class="source-line-no">053</span><span id="line-53">import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;</span>
+<span class="source-line-no">054</span><span id="line-54">import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;</span>
+<span class="source-line-no">055</span><span id="line-55">import org.apache.hadoop.hbase.testclassification.ClientTests;</span>
+<span class="source-line-no">056</span><span id="line-56">import org.apache.hadoop.hbase.testclassification.LargeTests;</span>
+<span class="source-line-no">057</span><span id="line-57">import org.apache.hadoop.hbase.util.Bytes;</span>
+<span class="source-line-no">058</span><span id="line-58">import org.apache.hadoop.hbase.util.CommonFSUtils;</span>
+<span class="source-line-no">059</span><span id="line-59">import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;</span>
+<span class="source-line-no">060</span><span id="line-60">import org.apache.hadoop.hbase.util.FSUtils;</span>
+<span class="source-line-no">061</span><span id="line-61">import org.apache.hadoop.hbase.util.HFileArchiveUtil;</span>
+<span class="source-line-no">062</span><span id="line-62">import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;</span>
+<span class="source-line-no">063</span><span id="line-63">import org.junit.jupiter.api.AfterEach;</span>
+<span class="source-line-no">064</span><span id="line-64">import org.junit.jupiter.api.BeforeEach;</span>
+<span class="source-line-no">065</span><span id="line-65">import org.junit.jupiter.api.Tag;</span>
+<span class="source-line-no">066</span><span id="line-66">import org.junit.jupiter.api.Test;</span>
+<span class="source-line-no">067</span><span id="line-67">import org.junit.jupiter.api.TestInfo;</span>
+<span class="source-line-no">068</span><span id="line-68">import org.slf4j.Logger;</span>
+<span class="source-line-no">069</span><span id="line-69">import org.slf4j.LoggerFactory;</span>
+<span class="source-line-no">070</span><span id="line-70"></span>
+<span class="source-line-no">071</span><span id="line-71">@Tag(LargeTests.TAG)</span>
+<span class="source-line-no">072</span><span id="line-72">@Tag(ClientTests.TAG)</span>
+<span class="source-line-no">073</span><span id="line-73">public class TestTableSnapshotScanner {</span>
+<span class="source-line-no">074</span><span id="line-74"></span>
+<span class="source-line-no">075</span><span id="line-75">  private static final Logger LOG = LoggerFactory.getLogger(TestTableSnapshotScanner.class);</span>
+<span class="source-line-no">076</span><span id="line-76">  private final HBaseTestingUtil UTIL = new HBaseTestingUtil();</span>
+<span class="source-line-no">077</span><span id="line-77">  private static final int NUM_REGION_SERVERS = 2;</span>
+<span class="source-line-no">078</span><span id="line-78">  private static final byte[][] FAMILIES = { Bytes.toBytes("f1"), Bytes.toBytes("f2") };</span>
+<span class="source-line-no">079</span><span id="line-79">  public static byte[] bbb = Bytes.toBytes("bbb");</span>
+<span class="source-line-no">080</span><span id="line-80">  public static byte[] yyy = Bytes.toBytes("yyy");</span>
+<span class="source-line-no">081</span><span id="line-81"></span>
+<span class="source-line-no">082</span><span id="line-82">  private FileSystem fs;</span>
+<span class="source-line-no">083</span><span id="line-83">  private Path rootDir;</span>
+<span class="source-line-no">084</span><span id="line-84">  private boolean clusterUp;</span>
+<span class="source-line-no">085</span><span id="line-85"></span>
+<span class="source-line-no">086</span><span id="line-86">  private String methodName;</span>
+<span class="source-line-no">087</span><span id="line-87"></span>
+<span class="source-line-no">088</span><span id="line-88">  public static void blockUntilSplitFinished(HBaseTestingUtil util, TableName tableName,</span>
+<span class="source-line-no">089</span><span id="line-89">    int expectedRegionSize) throws Exception {</span>
+<span class="source-line-no">090</span><span id="line-90">    for (int i = 0; i &lt; 100; i++) {</span>
+<span class="source-line-no">091</span><span id="line-91">      List&lt;RegionInfo&gt; hRegionInfoList = util.getAdmin().getRegions(tableName);</span>
+<span class="source-line-no">092</span><span id="line-92">      if (hRegionInfoList.size() &gt;= expectedRegionSize) {</span>
+<span class="source-line-no">093</span><span id="line-93">        break;</span>
+<span class="source-line-no">094</span><span id="line-94">      }</span>
+<span class="source-line-no">095</span><span id="line-95">      Thread.sleep(1000);</span>
+<span class="source-line-no">096</span><span id="line-96">    }</span>
+<span class="source-line-no">097</span><span id="line-97">  }</span>
+<span class="source-line-no">098</span><span id="line-98"></span>
+<span class="source-line-no">099</span><span id="line-99">  @BeforeEach</span>
+<span class="source-line-no">100</span><span id="line-100">  public void setupCluster(TestInfo testInfo) throws Exception {</span>
+<span class="source-line-no">101</span><span id="line-101">    methodName = testInfo.getTestMethod().get().getName();</span>
+<span class="source-line-no">102</span><span id="line-102">    setupConf(UTIL.getConfiguration());</span>
+<span class="source-line-no">103</span><span id="line-103">    StartTestingClusterOption option =</span>
+<span class="source-line-no">104</span><span id="line-104">      StartTestingClusterOption.builder().numRegionServers(NUM_REGION_SERVERS)</span>
+<span class="source-line-no">105</span><span id="line-105">        .numDataNodes(NUM_REGION_SERVERS).createRootDir(true).build();</span>
+<span class="source-line-no">106</span><span id="line-106">    UTIL.startMiniCluster(option);</span>
+<span class="source-line-no">107</span><span id="line-107">    clusterUp = true;</span>
+<span class="source-line-no">108</span><span id="line-108">    rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
+<span class="source-line-no">109</span><span id="line-109">    fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
+<span class="source-line-no">110</span><span id="line-110">  }</span>
+<span class="source-line-no">111</span><span id="line-111"></span>
+<span class="source-line-no">112</span><span id="line-112">  @AfterEach</span>
+<span class="source-line-no">113</span><span id="line-113">  public void tearDownCluster() throws Exception {</span>
+<span class="source-line-no">114</span><span id="line-114">    if (clusterUp) {</span>
+<span class="source-line-no">115</span><span id="line-115">      UTIL.shutdownMiniCluster();</span>
+<span class="source-line-no">116</span><span id="line-116">    }</span>
+<span class="source-line-no">117</span><span id="line-117">  }</span>
+<span class="source-line-no">118</span><span id="line-118"></span>
+<span class="source-line-no">119</span><span id="line-119">  protected void setupConf(Configuration conf) {</span>
+<span class="source-line-no">120</span><span id="line-120">    // Enable snapshot</span>
+<span class="source-line-no">121</span><span id="line-121">    conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);</span>
+<span class="source-line-no">122</span><span id="line-122">  }</span>
+<span class="source-line-no">123</span><span id="line-123"></span>
+<span class="source-line-no">124</span><span id="line-124">  public static void createTableAndSnapshot(HBaseTestingUtil util, TableName tableName,</span>
+<span class="source-line-no">125</span><span id="line-125">    String snapshotName, int numRegions) throws Exception {</span>
+<span class="source-line-no">126</span><span id="line-126">    try {</span>
+<span class="source-line-no">127</span><span id="line-127">      util.deleteTable(tableName);</span>
+<span class="source-line-no">128</span><span id="line-128">    } catch (Exception ex) {</span>
+<span class="source-line-no">129</span><span id="line-129">      // ignore</span>
+<span class="source-line-no">130</span><span id="line-130">    }</span>
+<span class="source-line-no">131</span><span id="line-131"></span>
+<span class="source-line-no">132</span><span id="line-132">    if (numRegions &gt; 1) {</span>
+<span class="source-line-no">133</span><span id="line-133">      util.createTable(tableName, FAMILIES, 1, bbb, yyy, numRegions);</span>
+<span class="source-line-no">134</span><span id="line-134">    } else {</span>
+<span class="source-line-no">135</span><span id="line-135">      util.createTable(tableName, FAMILIES);</span>
+<span class="source-line-no">136</span><span id="line-136">    }</span>
+<span class="source-line-no">137</span><span id="line-137">    Admin admin = util.getAdmin();</span>
+<span class="source-line-no">138</span><span id="line-138"></span>
+<span class="source-line-no">139</span><span id="line-139">    // put some stuff in the table</span>
+<span class="source-line-no">140</span><span id="line-140">    Table table = util.getConnection().getTable(tableName);</span>
+<span class="source-line-no">141</span><span id="line-141">    util.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">142</span><span id="line-142"></span>
+<span class="source-line-no">143</span><span id="line-143">    Path rootDir = CommonFSUtils.getRootDir(util.getConfiguration());</span>
+<span class="source-line-no">144</span><span id="line-144">    FileSystem fs = rootDir.getFileSystem(util.getConfiguration());</span>
+<span class="source-line-no">145</span><span id="line-145"></span>
+<span class="source-line-no">146</span><span id="line-146">    SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES), null,</span>
+<span class="source-line-no">147</span><span id="line-147">      snapshotName, rootDir, fs, true);</span>
+<span class="source-line-no">148</span><span id="line-148"></span>
+<span class="source-line-no">149</span><span id="line-149">    // load different values</span>
+<span class="source-line-no">150</span><span id="line-150">    byte[] value = Bytes.toBytes("after_snapshot_value");</span>
+<span class="source-line-no">151</span><span id="line-151">    util.loadTable(table, FAMILIES, value);</span>
+<span class="source-line-no">152</span><span id="line-152"></span>
+<span class="source-line-no">153</span><span id="line-153">    // cause flush to create new files in the region</span>
+<span class="source-line-no">154</span><span id="line-154">    admin.flush(tableName);</span>
+<span class="source-line-no">155</span><span id="line-155">    table.close();</span>
+<span class="source-line-no">156</span><span id="line-156">  }</span>
+<span class="source-line-no">157</span><span id="line-157"></span>
+<span class="source-line-no">158</span><span id="line-158">  @Test</span>
+<span class="source-line-no">159</span><span id="line-159">  public void testNoDuplicateResultsWhenSplitting() throws Exception {</span>
+<span class="source-line-no">160</span><span id="line-160">    TableName tableName = TableName.valueOf("testNoDuplicateResultsWhenSplitting");</span>
+<span class="source-line-no">161</span><span id="line-161">    String snapshotName = "testSnapshotBug";</span>
+<span class="source-line-no">162</span><span id="line-162">    try {</span>
+<span class="source-line-no">163</span><span id="line-163">      if (UTIL.getAdmin().tableExists(tableName)) {</span>
+<span class="source-line-no">164</span><span id="line-164">        UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">165</span><span id="line-165">      }</span>
+<span class="source-line-no">166</span><span id="line-166"></span>
+<span class="source-line-no">167</span><span id="line-167">      UTIL.createTable(tableName, FAMILIES);</span>
+<span class="source-line-no">168</span><span id="line-168">      Admin admin = UTIL.getAdmin();</span>
+<span class="source-line-no">169</span><span id="line-169"></span>
+<span class="source-line-no">170</span><span id="line-170">      // put some stuff in the table</span>
+<span class="source-line-no">171</span><span id="line-171">      Table table = UTIL.getConnection().getTable(tableName);</span>
+<span class="source-line-no">172</span><span id="line-172">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">173</span><span id="line-173"></span>
+<span class="source-line-no">174</span><span id="line-174">      // split to 2 regions</span>
+<span class="source-line-no">175</span><span id="line-175">      admin.split(tableName, Bytes.toBytes("eee"));</span>
+<span class="source-line-no">176</span><span id="line-176">      blockUntilSplitFinished(UTIL, tableName, 2);</span>
+<span class="source-line-no">177</span><span id="line-177"></span>
+<span class="source-line-no">178</span><span id="line-178">      Path rootDir = CommonFSUtils.getRootDir(UTIL.getConfiguration());</span>
+<span class="source-line-no">179</span><span id="line-179">      FileSystem fs = rootDir.getFileSystem(UTIL.getConfiguration());</span>
+<span class="source-line-no">180</span><span id="line-180"></span>
+<span class="source-line-no">181</span><span id="line-181">      SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName, Arrays.asList(FAMILIES),</span>
+<span class="source-line-no">182</span><span id="line-182">        null, snapshotName, rootDir, fs, true);</span>
+<span class="source-line-no">183</span><span id="line-183"></span>
+<span class="source-line-no">184</span><span id="line-184">      // load different values</span>
+<span class="source-line-no">185</span><span id="line-185">      byte[] value = Bytes.toBytes("after_snapshot_value");</span>
+<span class="source-line-no">186</span><span id="line-186">      UTIL.loadTable(table, FAMILIES, value);</span>
+<span class="source-line-no">187</span><span id="line-187"></span>
+<span class="source-line-no">188</span><span id="line-188">      // cause flush to create new files in the region</span>
+<span class="source-line-no">189</span><span id="line-189">      admin.flush(tableName);</span>
+<span class="source-line-no">190</span><span id="line-190">      table.close();</span>
+<span class="source-line-no">191</span><span id="line-191"></span>
+<span class="source-line-no">192</span><span id="line-192">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">193</span><span id="line-193">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">194</span><span id="line-194"></span>
+<span class="source-line-no">195</span><span id="line-195">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">196</span><span id="line-196">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">197</span><span id="line-197"></span>
+<span class="source-line-no">198</span><span id="line-198">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">199</span><span id="line-199">      scanner.close();</span>
+<span class="source-line-no">200</span><span id="line-200">    } catch (Exception e) {</span>
+<span class="source-line-no">201</span><span id="line-201">      e.printStackTrace();</span>
+<span class="source-line-no">202</span><span id="line-202">    } finally {</span>
+<span class="source-line-no">203</span><span id="line-203">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">204</span><span id="line-204">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">205</span><span id="line-205">    }</span>
+<span class="source-line-no">206</span><span id="line-206">  }</span>
+<span class="source-line-no">207</span><span id="line-207"></span>
+<span class="source-line-no">208</span><span id="line-208">  @Test</span>
+<span class="source-line-no">209</span><span id="line-209">  public void testScanLimit() throws Exception {</span>
+<span class="source-line-no">210</span><span id="line-210">    final TableName tableName = TableName.valueOf(methodName);</span>
+<span class="source-line-no">211</span><span id="line-211">    final String snapshotName = tableName + "Snapshot";</span>
+<span class="source-line-no">212</span><span id="line-212">    TableSnapshotScanner scanner = null;</span>
+<span class="source-line-no">213</span><span id="line-213">    try {</span>
+<span class="source-line-no">214</span><span id="line-214">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">215</span><span id="line-215">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">216</span><span id="line-216">      Scan scan = new Scan().withStartRow(bbb).setLimit(100); // limit the scan</span>
+<span class="source-line-no">217</span><span id="line-217"></span>
+<span class="source-line-no">218</span><span id="line-218">      scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">219</span><span id="line-219">      int count = 0;</span>
+<span class="source-line-no">220</span><span id="line-220">      while (true) {</span>
+<span class="source-line-no">221</span><span id="line-221">        Result result = scanner.next();</span>
+<span class="source-line-no">222</span><span id="line-222">        if (result == null) {</span>
+<span class="source-line-no">223</span><span id="line-223">          break;</span>
+<span class="source-line-no">224</span><span id="line-224">        }</span>
+<span class="source-line-no">225</span><span id="line-225">        count++;</span>
+<span class="source-line-no">226</span><span id="line-226">      }</span>
+<span class="source-line-no">227</span><span id="line-227">      assertEquals(100, count);</span>
+<span class="source-line-no">228</span><span id="line-228">    } finally {</span>
+<span class="source-line-no">229</span><span id="line-229">      if (scanner != null) {</span>
+<span class="source-line-no">230</span><span id="line-230">        scanner.close();</span>
+<span class="source-line-no">231</span><span id="line-231">      }</span>
+<span class="source-line-no">232</span><span id="line-232">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">233</span><span id="line-233">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">234</span><span id="line-234">    }</span>
+<span class="source-line-no">235</span><span id="line-235">  }</span>
+<span class="source-line-no">236</span><span id="line-236"></span>
+<span class="source-line-no">237</span><span id="line-237">  @Test</span>
+<span class="source-line-no">238</span><span id="line-238">  public void testWithSingleRegion() throws Exception {</span>
+<span class="source-line-no">239</span><span id="line-239">    testScanner(UTIL, "testWithSingleRegion", 1, false);</span>
+<span class="source-line-no">240</span><span id="line-240">  }</span>
+<span class="source-line-no">241</span><span id="line-241"></span>
+<span class="source-line-no">242</span><span id="line-242">  @Test</span>
+<span class="source-line-no">243</span><span id="line-243">  public void testWithMultiRegion() throws Exception {</span>
+<span class="source-line-no">244</span><span id="line-244">    testScanner(UTIL, "testWithMultiRegion", 10, false);</span>
+<span class="source-line-no">245</span><span id="line-245">  }</span>
+<span class="source-line-no">246</span><span id="line-246"></span>
+<span class="source-line-no">247</span><span id="line-247">  @Test</span>
+<span class="source-line-no">248</span><span id="line-248">  public void testWithOfflineHBaseMultiRegion() throws Exception {</span>
+<span class="source-line-no">249</span><span id="line-249">    testScanner(UTIL, "testWithMultiRegion", 20, true);</span>
+<span class="source-line-no">250</span><span id="line-250">  }</span>
+<span class="source-line-no">251</span><span id="line-251"></span>
+<span class="source-line-no">252</span><span id="line-252">  private ScanMetrics createTableSnapshotScannerAndGetScanMetrics(boolean enableScanMetrics,</span>
+<span class="source-line-no">253</span><span id="line-253">    boolean enableScanMetricsByRegion, byte[] endKey) throws Exception {</span>
+<span class="source-line-no">254</span><span id="line-254">    TableName tableName = TableName.valueOf(methodName + "_TABLE");</span>
+<span class="source-line-no">255</span><span id="line-255">    String snapshotName = methodName + "_SNAPSHOT";</span>
+<span class="source-line-no">256</span><span id="line-256">    try {</span>
+<span class="source-line-no">257</span><span id="line-257">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">258</span><span id="line-258">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">259</span><span id="line-259">      Scan scan = new Scan().withStartRow(bbb).withStopRow(endKey);</span>
+<span class="source-line-no">260</span><span id="line-260">      scan.setScanMetricsEnabled(enableScanMetrics);</span>
+<span class="source-line-no">261</span><span id="line-261">      scan.setEnableScanMetricsByRegion(enableScanMetricsByRegion);</span>
+<span class="source-line-no">262</span><span id="line-262">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">263</span><span id="line-263"></span>
+<span class="source-line-no">264</span><span id="line-264">      TableSnapshotScanner snapshotScanner =</span>
+<span class="source-line-no">265</span><span id="line-265">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">266</span><span id="line-266">      verifyScanner(snapshotScanner, bbb, endKey);</span>
+<span class="source-line-no">267</span><span id="line-267">      return snapshotScanner.getScanMetrics();</span>
+<span class="source-line-no">268</span><span id="line-268">    } finally {</span>
+<span class="source-line-no">269</span><span id="line-269">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">270</span><span id="line-270">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">271</span><span id="line-271">    }</span>
+<span class="source-line-no">272</span><span id="line-272">  }</span>
+<span class="source-line-no">273</span><span id="line-273"></span>
+<span class="source-line-no">274</span><span id="line-274">  @Test</span>
+<span class="source-line-no">275</span><span id="line-275">  public void testScanMetricsDisabled() throws Exception {</span>
+<span class="source-line-no">276</span><span id="line-276">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(false, false, yyy);</span>
+<span class="source-line-no">277</span><span id="line-277">    assertNull(scanMetrics);</span>
+<span class="source-line-no">278</span><span id="line-278">  }</span>
+<span class="source-line-no">279</span><span id="line-279"></span>
+<span class="source-line-no">280</span><span id="line-280">  @Test</span>
+<span class="source-line-no">281</span><span id="line-281">  public void testScanMetricsWithScanMetricsByRegionDisabled() throws Exception {</span>
+<span class="source-line-no">282</span><span id="line-282">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, false, yyy);</span>
+<span class="source-line-no">283</span><span id="line-283">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">284</span><span id="line-284">    int rowsScanned = 0;</span>
+<span class="source-line-no">285</span><span id="line-285">    for (byte[] row : HBaseTestingUtil.ROWS) {</span>
+<span class="source-line-no">286</span><span id="line-286">      if (Bytes.compareTo(row, bbb) &gt;= 0 &amp;&amp; Bytes.compareTo(row, yyy) &lt; 0) {</span>
+<span class="source-line-no">287</span><span id="line-287">        rowsScanned++;</span>
+<span class="source-line-no">288</span><span id="line-288">      }</span>
+<span class="source-line-no">289</span><span id="line-289">    }</span>
+<span class="source-line-no">290</span><span id="line-290">    Map&lt;String, Long&gt; metricsMap = scanMetrics.getMetricsMap();</span>
+<span class="source-line-no">291</span><span id="line-291">    assertEquals(rowsScanned, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
+<span class="source-line-no">292</span><span id="line-292">  }</span>
+<span class="source-line-no">293</span><span id="line-293"></span>
+<span class="source-line-no">294</span><span id="line-294">  @Test</span>
+<span class="source-line-no">295</span><span id="line-295">  public void testScanMetricsByRegionForSingleRegion() throws Exception {</span>
+<span class="source-line-no">296</span><span id="line-296">    // Scan single row with row key bbb</span>
+<span class="source-line-no">297</span><span id="line-297">    byte[] bbc = Bytes.toBytes("bbc");</span>
+<span class="source-line-no">298</span><span id="line-298">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, bbc);</span>
+<span class="source-line-no">299</span><span id="line-299">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">300</span><span id="line-300">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
+<span class="source-line-no">301</span><span id="line-301">      scanMetrics.collectMetricsByRegion();</span>
+<span class="source-line-no">302</span><span id="line-302">    assertEquals(1, scanMetricsByRegion.size());</span>
+<span class="source-line-no">303</span><span id="line-303">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
+<span class="source-line-no">304</span><span id="line-304">      .entrySet()) {</span>
+<span class="source-line-no">305</span><span id="line-305">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
+<span class="source-line-no">306</span><span id="line-306">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
+<span class="source-line-no">307</span><span id="line-307">      assertNull(scanMetricsRegionInfo.getServerName());</span>
+<span class="source-line-no">308</span><span id="line-308">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
+<span class="source-line-no">309</span><span id="line-309">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
+<span class="source-line-no">310</span><span id="line-310">      assertEquals(1, (long) metricsMap.get(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME));</span>
+<span class="source-line-no">311</span><span id="line-311">    }</span>
+<span class="source-line-no">312</span><span id="line-312">  }</span>
+<span class="source-line-no">313</span><span id="line-313"></span>
+<span class="source-line-no">314</span><span id="line-314">  @Test</span>
+<span class="source-line-no">315</span><span id="line-315">  public void testScanMetricsByRegionForMultiRegion() throws Exception {</span>
+<span class="source-line-no">316</span><span id="line-316">    ScanMetrics scanMetrics = createTableSnapshotScannerAndGetScanMetrics(true, true, yyy);</span>
+<span class="source-line-no">317</span><span id="line-317">    assertNotNull(scanMetrics);</span>
+<span class="source-line-no">318</span><span id="line-318">    Map&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; scanMetricsByRegion =</span>
+<span class="source-line-no">319</span><span id="line-319">      scanMetrics.collectMetricsByRegion();</span>
+<span class="source-line-no">320</span><span id="line-320">    for (Map.Entry&lt;ScanMetricsRegionInfo, Map&lt;String, Long&gt;&gt; entry : scanMetricsByRegion</span>
+<span class="source-line-no">321</span><span id="line-321">      .entrySet()) {</span>
+<span class="source-line-no">322</span><span id="line-322">      ScanMetricsRegionInfo scanMetricsRegionInfo = entry.getKey();</span>
+<span class="source-line-no">323</span><span id="line-323">      Map&lt;String, Long&gt; metricsMap = entry.getValue();</span>
+<span class="source-line-no">324</span><span id="line-324">      assertNull(scanMetricsRegionInfo.getServerName());</span>
+<span class="source-line-no">325</span><span id="line-325">      assertNotNull(scanMetricsRegionInfo.getEncodedRegionName());</span>
+<span class="source-line-no">326</span><span id="line-326">      assertEquals(1, (long) metricsMap.get(REGIONS_SCANNED_METRIC_NAME));</span>
+<span class="source-line-no">327</span><span id="line-327">    }</span>
+<span class="source-line-no">328</span><span id="line-328">  }</span>
+<span class="source-line-no">329</span><span id="line-329"></span>
+<span class="source-line-no">330</span><span id="line-330">  @Test</span>
+<span class="source-line-no">331</span><span id="line-331">  public void testScannerWithRestoreScanner() throws Exception {</span>
+<span class="source-line-no">332</span><span id="line-332">    TableName tableName = TableName.valueOf("testScanner");</span>
+<span class="source-line-no">333</span><span id="line-333">    String snapshotName = "testScannerWithRestoreScanner";</span>
+<span class="source-line-no">334</span><span id="line-334">    try {</span>
+<span class="source-line-no">335</span><span id="line-335">      createTableAndSnapshot(UTIL, tableName, snapshotName, 50);</span>
+<span class="source-line-no">336</span><span id="line-336">      Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">337</span><span id="line-337">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">338</span><span id="line-338"></span>
+<span class="source-line-no">339</span><span id="line-339">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">340</span><span id="line-340">      Path rootDir = CommonFSUtils.getRootDir(conf);</span>
+<span class="source-line-no">341</span><span id="line-341"></span>
+<span class="source-line-no">342</span><span id="line-342">      TableSnapshotScanner scanner0 =</span>
+<span class="source-line-no">343</span><span id="line-343">        new TableSnapshotScanner(conf, restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">344</span><span id="line-344">      verifyScanner(scanner0, bbb, yyy);</span>
+<span class="source-line-no">345</span><span id="line-345">      scanner0.close();</span>
+<span class="source-line-no">346</span><span id="line-346"></span>
+<span class="source-line-no">347</span><span id="line-347">      // restore snapshot.</span>
+<span class="source-line-no">348</span><span id="line-348">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">349</span><span id="line-349"></span>
+<span class="source-line-no">350</span><span id="line-350">      // scan the snapshot without restoring snapshot</span>
+<span class="source-line-no">351</span><span id="line-351">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">352</span><span id="line-352">        new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">353</span><span id="line-353">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">354</span><span id="line-354">      scanner.close();</span>
+<span class="source-line-no">355</span><span id="line-355"></span>
+<span class="source-line-no">356</span><span id="line-356">      // check whether the snapshot has been deleted by the close of scanner.</span>
+<span class="source-line-no">357</span><span id="line-357">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">358</span><span id="line-358">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">359</span><span id="line-359">      scanner.close();</span>
+<span class="source-line-no">360</span><span id="line-360"></span>
+<span class="source-line-no">361</span><span id="line-361">      // restore snapshot again.</span>
+<span class="source-line-no">362</span><span id="line-362">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">363</span><span id="line-363"></span>
+<span class="source-line-no">364</span><span id="line-364">      // check whether the snapshot has been deleted by the close of scanner.</span>
+<span class="source-line-no">365</span><span id="line-365">      scanner = new TableSnapshotScanner(conf, rootDir, restoreDir, snapshotName, scan, true);</span>
+<span class="source-line-no">366</span><span id="line-366">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">367</span><span id="line-367">      scanner.close();</span>
+<span class="source-line-no">368</span><span id="line-368">    } finally {</span>
+<span class="source-line-no">369</span><span id="line-369">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">370</span><span id="line-370">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">371</span><span id="line-371">    }</span>
+<span class="source-line-no">372</span><span id="line-372">  }</span>
+<span class="source-line-no">373</span><span id="line-373"></span>
+<span class="source-line-no">374</span><span id="line-374">  @Test</span>
+<span class="source-line-no">375</span><span id="line-375">  public void testScannerWithRestoredMobSnapshot() throws Exception {</span>
+<span class="source-line-no">376</span><span id="line-376">    TableName tableName = TableName.valueOf(methodName);</span>
+<span class="source-line-no">377</span><span id="line-377">    String snapshotName = methodName + "Snapshot";</span>
+<span class="source-line-no">378</span><span id="line-378">    Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">379</span><span id="line-379">    try {</span>
+<span class="source-line-no">380</span><span id="line-380">      MobSnapshotTestingUtils.createMobTable(UTIL, tableName, new byte[0][], 1, FAMILIES);</span>
+<span class="source-line-no">381</span><span id="line-381">      try (Table table = UTIL.getConnection().getTable(tableName)) {</span>
+<span class="source-line-no">382</span><span id="line-382">        UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">383</span><span id="line-383">      }</span>
+<span class="source-line-no">384</span><span id="line-384">      UTIL.getAdmin().snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">385</span><span id="line-385"></span>
+<span class="source-line-no">386</span><span id="line-386">      Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">387</span><span id="line-387">      RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName);</span>
+<span class="source-line-no">388</span><span id="line-388">      try (TableSnapshotScanner scanner = new TableSnapshotScanner(conf, rootDir, restoreDir,</span>
+<span class="source-line-no">389</span><span id="line-389">        snapshotName, new Scan().withStartRow(Bytes.toBytes("zzzz")), true)) {</span>
+<span class="source-line-no">390</span><span id="line-390">        assertNull(scanner.next());</span>
+<span class="source-line-no">391</span><span id="line-391">      }</span>
 <span class="source-line-no">392</span><span id="line-392">    } finally {</span>
-<span class="source-line-no">393</span><span id="line-393">      if (clusterUp) {</span>
-<span class="source-line-no">394</span><span id="line-394">        util.getAdmin().deleteSnapshot(snapshotName);</span>
-<span class="source-line-no">395</span><span id="line-395">        util.deleteTable(tableName);</span>
-<span class="source-line-no">396</span><span id="line-396">      }</span>
-<span class="source-line-no">397</span><span id="line-397">    }</span>
-<span class="source-line-no">398</span><span id="line-398">  }</span>
-<span class="source-line-no">399</span><span id="line-399"></span>
-<span class="source-line-no">400</span><span id="line-400">  private void verifyScanner(ResultScanner scanner, byte[] startRow, byte[] stopRow)</span>
-<span class="source-line-no">401</span><span id="line-401">    throws IOException, InterruptedException {</span>
-<span class="source-line-no">402</span><span id="line-402"></span>
-<span class="source-line-no">403</span><span id="line-403">    HBaseTestingUtil.SeenRowTracker rowTracker =</span>
-<span class="source-line-no">404</span><span id="line-404">      new HBaseTestingUtil.SeenRowTracker(startRow, stopRow);</span>
-<span class="source-line-no">405</span><span id="line-405"></span>
-<span class="source-line-no">406</span><span id="line-406">    while (true) {</span>
-<span class="source-line-no">407</span><span id="line-407">      Result result = scanner.next();</span>
-<span class="source-line-no">408</span><span id="line-408">      if (result == null) {</span>
-<span class="source-line-no">409</span><span id="line-409">        break;</span>
-<span class="source-line-no">410</span><span id="line-410">      }</span>
-<span class="source-line-no">411</span><span id="line-411">      verifyRow(result);</span>
-<span class="source-line-no">412</span><span id="line-412">      rowTracker.addRow(result.getRow());</span>
-<span class="source-line-no">413</span><span id="line-413">    }</span>
-<span class="source-line-no">414</span><span id="line-414"></span>
-<span class="source-line-no">415</span><span id="line-415">    // validate all rows are seen</span>
-<span class="source-line-no">416</span><span id="line-416">    rowTracker.validate();</span>
-<span class="source-line-no">417</span><span id="line-417">  }</span>
-<span class="source-line-no">418</span><span id="line-418"></span>
-<span class="source-line-no">419</span><span id="line-419">  private static void verifyRow(Result result) throws IOException {</span>
-<span class="source-line-no">420</span><span id="line-420">    byte[] row = result.getRow();</span>
-<span class="source-line-no">421</span><span id="line-421">    CellScanner scanner = result.cellScanner();</span>
-<span class="source-line-no">422</span><span id="line-422">    while (scanner.advance()) {</span>
-<span class="source-line-no">423</span><span id="line-423">      Cell cell = scanner.current();</span>
-<span class="source-line-no">424</span><span id="line-424"></span>
-<span class="source-line-no">425</span><span id="line-425">      // assert that all Cells in the Result have the same key</span>
-<span class="source-line-no">426</span><span id="line-426">      assertEquals(0, Bytes.compareTo(row, 0, row.length, cell.getRowArray(), cell.getRowOffset(),</span>
-<span class="source-line-no">427</span><span id="line-427">        cell.getRowLength()));</span>
-<span class="source-line-no">428</span><span id="line-428">    }</span>
-<span class="source-line-no">429</span><span id="line-429"></span>
-<span class="source-line-no">430</span><span id="line-430">    for (int j = 0; j &lt; FAMILIES.length; j++) {</span>
-<span class="source-line-no">431</span><span id="line-431">      byte[] actual = result.getValue(FAMILIES[j], FAMILIES[j]);</span>
-<span class="source-line-no">432</span><span id="line-432">      assertArrayEquals(row, actual, "Row in snapshot does not match, expected:"</span>
-<span class="source-line-no">433</span><span id="line-433">        + Bytes.toString(row) + " ,actual:" + Bytes.toString(actual));</span>
-<span class="source-line-no">434</span><span id="line-434">    }</span>
-<span class="source-line-no">435</span><span id="line-435">  }</span>
-<span class="source-line-no">436</span><span id="line-436"></span>
-<span class="source-line-no">437</span><span id="line-437">  @Test</span>
-<span class="source-line-no">438</span><span id="line-438">  public void testMergeRegion() throws Exception {</span>
-<span class="source-line-no">439</span><span id="line-439">    TableName tableName = TableName.valueOf("testMergeRegion");</span>
-<span class="source-line-no">440</span><span id="line-440">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
-<span class="source-line-no">441</span><span id="line-441">    Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">442</span><span id="line-442">    Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
-<span class="source-line-no">443</span><span id="line-443">    long timeout = 20000; // 20s</span>
-<span class="source-line-no">444</span><span id="line-444">    try (Admin admin = UTIL.getAdmin()) {</span>
-<span class="source-line-no">445</span><span id="line-445">      List&lt;String&gt; serverList = admin.getRegionServers().stream().map(sn -&gt; sn.getServerName())</span>
-<span class="source-line-no">446</span><span id="line-446">        .collect(Collectors.toList());</span>
-<span class="source-line-no">447</span><span id="line-447">      // create table with 3 regions</span>
-<span class="source-line-no">448</span><span id="line-448">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
-<span class="source-line-no">449</span><span id="line-449">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">450</span><span id="line-450">      assertEquals(3, regions.size());</span>
-<span class="source-line-no">451</span><span id="line-451">      RegionInfo region0 = regions.get(0);</span>
-<span class="source-line-no">452</span><span id="line-452">      RegionInfo region1 = regions.get(1);</span>
-<span class="source-line-no">453</span><span id="line-453">      RegionInfo region2 = regions.get(2);</span>
-<span class="source-line-no">454</span><span id="line-454">      // put some data in the table</span>
-<span class="source-line-no">455</span><span id="line-455">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">456</span><span id="line-456">      admin.flush(tableName);</span>
-<span class="source-line-no">457</span><span id="line-457">      // wait flush is finished</span>
-<span class="source-line-no">458</span><span id="line-458">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">459</span><span id="line-459">        try {</span>
-<span class="source-line-no">460</span><span id="line-460">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">461</span><span id="line-461">          for (RegionInfo region : regions) {</span>
-<span class="source-line-no">462</span><span id="line-462">            Path regionDir = new Path(tableDir, region.getEncodedName());</span>
-<span class="source-line-no">463</span><span id="line-463">            for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
-<span class="source-line-no">464</span><span id="line-464">              for (FileStatus fs : fs.listStatus(familyDir)) {</span>
-<span class="source-line-no">465</span><span id="line-465">                if (!fs.getPath().getName().equals(".filelist")) {</span>
-<span class="source-line-no">466</span><span id="line-466">                  return true;</span>
-<span class="source-line-no">467</span><span id="line-467">                }</span>
-<span class="source-line-no">468</span><span id="line-468">              }</span>
-<span class="source-line-no">469</span><span id="line-469">              return false;</span>
-<span class="source-line-no">470</span><span id="line-470">            }</span>
-<span class="source-line-no">471</span><span id="line-471">          }</span>
-<span class="source-line-no">472</span><span id="line-472">          return true;</span>
-<span class="source-line-no">473</span><span id="line-473">        } catch (IOException e) {</span>
-<span class="source-line-no">474</span><span id="line-474">          LOG.warn("Failed check if flush is finished", e);</span>
-<span class="source-line-no">475</span><span id="line-475">          return false;</span>
-<span class="source-line-no">476</span><span id="line-476">        }</span>
-<span class="source-line-no">477</span><span id="line-477">      });</span>
-<span class="source-line-no">478</span><span id="line-478">      // merge 2 regions</span>
-<span class="source-line-no">479</span><span id="line-479">      admin.compactionSwitch(false, serverList);</span>
-<span class="source-line-no">480</span><span id="line-480">      admin.mergeRegionsAsync(region0.getEncodedNameAsBytes(), region1.getEncodedNameAsBytes(),</span>
-<span class="source-line-no">481</span><span id="line-481">        true);</span>
-<span class="source-line-no">482</span><span id="line-482">      UTIL.waitFor(timeout, () -&gt; admin.getRegions(tableName).size() == 2);</span>
-<span class="source-line-no">483</span><span id="line-483">      List&lt;RegionInfo&gt; mergedRegions = admin.getRegions(tableName);</span>
-<span class="source-line-no">484</span><span id="line-484">      RegionInfo mergedRegion =</span>
-<span class="source-line-no">485</span><span id="line-485">        mergedRegions.get(0).getEncodedName().equals(region2.getEncodedName())</span>
-<span class="source-line-no">486</span><span id="line-486">          ? mergedRegions.get(1)</span>
-<span class="source-line-no">487</span><span id="line-487">          : mergedRegions.get(0);</span>
-<span class="source-line-no">488</span><span id="line-488">      // snapshot</span>
-<span class="source-line-no">489</span><span id="line-489">      admin.snapshot(snapshotName, tableName);</span>
-<span class="source-line-no">490</span><span id="line-490">      assertEquals(1, admin.listSnapshots().size());</span>
-<span class="source-line-no">491</span><span id="line-491">      // major compact</span>
-<span class="source-line-no">492</span><span id="line-492">      admin.compactionSwitch(true, serverList);</span>
-<span class="source-line-no">493</span><span id="line-493">      admin.majorCompactRegion(mergedRegion.getRegionName());</span>
-<span class="source-line-no">494</span><span id="line-494">      // wait until merged region has no reference</span>
-<span class="source-line-no">495</span><span id="line-495">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">496</span><span id="line-496">        try {</span>
-<span class="source-line-no">497</span><span id="line-497">          for (RegionServerThread regionServerThread : UTIL.getMiniHBaseCluster()</span>
-<span class="source-line-no">498</span><span id="line-498">            .getRegionServerThreads()) {</span>
-<span class="source-line-no">499</span><span id="line-499">            HRegionServer regionServer = regionServerThread.getRegionServer();</span>
-<span class="source-line-no">500</span><span id="line-500">            for (HRegion subRegion : regionServer.getRegions(tableName)) {</span>
-<span class="source-line-no">501</span><span id="line-501">              if (</span>
-<span class="source-line-no">502</span><span id="line-502">                subRegion.getRegionInfo().getEncodedName().equals(mergedRegion.getEncodedName())</span>
-<span class="source-line-no">503</span><span id="line-503">              ) {</span>
-<span class="source-line-no">504</span><span id="line-504">                regionServer.getCompactedHFilesDischarger().chore();</span>
-<span class="source-line-no">505</span><span id="line-505">              }</span>
-<span class="source-line-no">506</span><span id="line-506">            }</span>
-<span class="source-line-no">507</span><span id="line-507">          }</span>
-<span class="source-line-no">508</span><span id="line-508">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">509</span><span id="line-509">          HRegionFileSystem regionFs = HRegionFileSystem</span>
-<span class="source-line-no">510</span><span id="line-510">            .openRegionFromFileSystem(UTIL.getConfiguration(), fs, tableDir, mergedRegion, true);</span>
-<span class="source-line-no">511</span><span id="line-511">          boolean references = false;</span>
-<span class="source-line-no">512</span><span id="line-512">          Path regionDir = new Path(tableDir, mergedRegion.getEncodedName());</span>
-<span class="source-line-no">513</span><span id="line-513">          for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
-<span class="source-line-no">514</span><span id="line-514">            StoreContext storeContext = StoreContext.getBuilder()</span>
-<span class="source-line-no">515</span><span id="line-515">              .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.of(familyDir.getName()))</span>
-<span class="source-line-no">516</span><span id="line-516">              .withRegionFileSystem(regionFs).withFamilyStoreDirectoryPath(familyDir).build();</span>
-<span class="source-line-no">517</span><span id="line-517">            StoreFileTracker sft =</span>
-<span class="source-line-no">518</span><span id="line-518">              StoreFileTrackerFactory.create(UTIL.getConfiguration(), false, storeContext);</span>
-<span class="source-line-no">519</span><span id="line-519">            references = references || sft.hasReferences();</span>
-<span class="source-line-no">520</span><span id="line-520">            if (references) {</span>
-<span class="source-line-no">521</span><span id="line-521">              break;</span>
-<span class="source-line-no">522</span><span id="line-522">            }</span>
-<span class="source-line-no">523</span><span id="line-523">          }</span>
-<span class="source-line-no">524</span><span id="line-524">          return !references;</span>
-<span class="source-line-no">525</span><span id="line-525">        } catch (IOException e) {</span>
-<span class="source-line-no">526</span><span id="line-526">          LOG.warn("Failed check merged region has no reference", e);</span>
-<span class="source-line-no">527</span><span id="line-527">          return false;</span>
-<span class="source-line-no">528</span><span id="line-528">        }</span>
-<span class="source-line-no">529</span><span id="line-529">      });</span>
-<span class="source-line-no">530</span><span id="line-530">      // run catalog janitor to clean and wait for parent regions are archived</span>
-<span class="source-line-no">531</span><span id="line-531">      UTIL.getMiniHBaseCluster().getMaster().getCatalogJanitor().choreForTesting();</span>
-<span class="source-line-no">532</span><span id="line-532">      UTIL.waitFor(timeout, () -&gt; {</span>
-<span class="source-line-no">533</span><span id="line-533">        try {</span>
+<span class="source-line-no">393</span><span id="line-393">      fs.delete(restoreDir, true);</span>
+<span class="source-line-no">394</span><span id="line-394">      UTIL.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">395</span><span id="line-395">      UTIL.deleteTable(tableName);</span>
+<span class="source-line-no">396</span><span id="line-396">    }</span>
+<span class="source-line-no">397</span><span id="line-397">  }</span>
+<span class="source-line-no">398</span><span id="line-398"></span>
+<span class="source-line-no">399</span><span id="line-399">  private void testScanner(HBaseTestingUtil util, String snapshotName, int numRegions,</span>
+<span class="source-line-no">400</span><span id="line-400">    boolean shutdownCluster) throws Exception {</span>
+<span class="source-line-no">401</span><span id="line-401">    TableName tableName = TableName.valueOf("testScanner");</span>
+<span class="source-line-no">402</span><span id="line-402">    try {</span>
+<span class="source-line-no">403</span><span id="line-403">      createTableAndSnapshot(util, tableName, snapshotName, numRegions);</span>
+<span class="source-line-no">404</span><span id="line-404"></span>
+<span class="source-line-no">405</span><span id="line-405">      if (shutdownCluster) {</span>
+<span class="source-line-no">406</span><span id="line-406">        util.shutdownMiniHBaseCluster();</span>
+<span class="source-line-no">407</span><span id="line-407">        clusterUp = false;</span>
+<span class="source-line-no">408</span><span id="line-408">      }</span>
+<span class="source-line-no">409</span><span id="line-409"></span>
+<span class="source-line-no">410</span><span id="line-410">      Path restoreDir = util.getDataTestDirOnTestFS(snapshotName);</span>
+<span class="source-line-no">411</span><span id="line-411">      Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan</span>
+<span class="source-line-no">412</span><span id="line-412"></span>
+<span class="source-line-no">413</span><span id="line-413">      TableSnapshotScanner scanner =</span>
+<span class="source-line-no">414</span><span id="line-414">        new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);</span>
+<span class="source-line-no">415</span><span id="line-415"></span>
+<span class="source-line-no">416</span><span id="line-416">      verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">417</span><span id="line-417">      scanner.close();</span>
+<span class="source-line-no">418</span><span id="line-418">    } finally {</span>
+<span class="source-line-no">419</span><span id="line-419">      if (clusterUp) {</span>
+<span class="source-line-no">420</span><span id="line-420">        util.getAdmin().deleteSnapshot(snapshotName);</span>
+<span class="source-line-no">421</span><span id="line-421">        util.deleteTable(tableName);</span>
+<span class="source-line-no">422</span><span id="line-422">      }</span>
+<span class="source-line-no">423</span><span id="line-423">    }</span>
+<span class="source-line-no">424</span><span id="line-424">  }</span>
+<span class="source-line-no">425</span><span id="line-425"></span>
+<span class="source-line-no">426</span><span id="line-426">  private void verifyScanner(ResultScanner scanner, byte[] startRow, byte[] stopRow)</span>
+<span class="source-line-no">427</span><span id="line-427">    throws IOException, InterruptedException {</span>
+<span class="source-line-no">428</span><span id="line-428"></span>
+<span class="source-line-no">429</span><span id="line-429">    HBaseTestingUtil.SeenRowTracker rowTracker =</span>
+<span class="source-line-no">430</span><span id="line-430">      new HBaseTestingUtil.SeenRowTracker(startRow, stopRow);</span>
+<span class="source-line-no">431</span><span id="line-431"></span>
+<span class="source-line-no">432</span><span id="line-432">    while (true) {</span>
+<span class="source-line-no">433</span><span id="line-433">      Result result = scanner.next();</span>
+<span class="source-line-no">434</span><span id="line-434">      if (result == null) {</span>
+<span class="source-line-no">435</span><span id="line-435">        break;</span>
+<span class="source-line-no">436</span><span id="line-436">      }</span>
+<span class="source-line-no">437</span><span id="line-437">      verifyRow(result);</span>
+<span class="source-line-no">438</span><span id="line-438">      rowTracker.addRow(result.getRow());</span>
+<span class="source-line-no">439</span><span id="line-439">    }</span>
+<span class="source-line-no">440</span><span id="line-440"></span>
+<span class="source-line-no">441</span><span id="line-441">    // validate all rows are seen</span>
+<span class="source-line-no">442</span><span id="line-442">    rowTracker.validate();</span>
+<span class="source-line-no">443</span><span id="line-443">  }</span>
+<span class="source-line-no">444</span><span id="line-444"></span>
+<span class="source-line-no">445</span><span id="line-445">  private static void verifyRow(Result result) throws IOException {</span>
+<span class="source-line-no">446</span><span id="line-446">    byte[] row = result.getRow();</span>
+<span class="source-line-no">447</span><span id="line-447">    CellScanner scanner = result.cellScanner();</span>
+<span class="source-line-no">448</span><span id="line-448">    while (scanner.advance()) {</span>
+<span class="source-line-no">449</span><span id="line-449">      Cell cell = scanner.current();</span>
+<span class="source-line-no">450</span><span id="line-450"></span>
+<span class="source-line-no">451</span><span id="line-451">      // assert that all Cells in the Result have the same key</span>
+<span class="source-line-no">452</span><span id="line-452">      assertEquals(0, Bytes.compareTo(row, 0, row.length, cell.getRowArray(), cell.getRowOffset(),</span>
+<span class="source-line-no">453</span><span id="line-453">        cell.getRowLength()));</span>
+<span class="source-line-no">454</span><span id="line-454">    }</span>
+<span class="source-line-no">455</span><span id="line-455"></span>
+<span class="source-line-no">456</span><span id="line-456">    for (int j = 0; j &lt; FAMILIES.length; j++) {</span>
+<span class="source-line-no">457</span><span id="line-457">      byte[] actual = result.getValue(FAMILIES[j], FAMILIES[j]);</span>
+<span class="source-line-no">458</span><span id="line-458">      assertArrayEquals(row, actual, "Row in snapshot does not match, expected:"</span>
+<span class="source-line-no">459</span><span id="line-459">        + Bytes.toString(row) + " ,actual:" + Bytes.toString(actual));</span>
+<span class="source-line-no">460</span><span id="line-460">    }</span>
+<span class="source-line-no">461</span><span id="line-461">  }</span>
+<span class="source-line-no">462</span><span id="line-462"></span>
+<span class="source-line-no">463</span><span id="line-463">  @Test</span>
+<span class="source-line-no">464</span><span id="line-464">  public void testMergeRegion() throws Exception {</span>
+<span class="source-line-no">465</span><span id="line-465">    TableName tableName = TableName.valueOf("testMergeRegion");</span>
+<span class="source-line-no">466</span><span id="line-466">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
+<span class="source-line-no">467</span><span id="line-467">    Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">468</span><span id="line-468">    Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();</span>
+<span class="source-line-no">469</span><span id="line-469">    long timeout = 20000; // 20s</span>
+<span class="source-line-no">470</span><span id="line-470">    try (Admin admin = UTIL.getAdmin()) {</span>
+<span class="source-line-no">471</span><span id="line-471">      List&lt;String&gt; serverList = admin.getRegionServers().stream().map(sn -&gt; sn.getServerName())</span>
+<span class="source-line-no">472</span><span id="line-472">        .collect(Collectors.toList());</span>
+<span class="source-line-no">473</span><span id="line-473">      // create table with 3 regions</span>
+<span class="source-line-no">474</span><span id="line-474">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
+<span class="source-line-no">475</span><span id="line-475">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">476</span><span id="line-476">      assertEquals(3, regions.size());</span>
+<span class="source-line-no">477</span><span id="line-477">      RegionInfo region0 = regions.get(0);</span>
+<span class="source-line-no">478</span><span id="line-478">      RegionInfo region1 = regions.get(1);</span>
+<span class="source-line-no">479</span><span id="line-479">      RegionInfo region2 = regions.get(2);</span>
+<span class="source-line-no">480</span><span id="line-480">      // put some data in the table</span>
+<span class="source-line-no">481</span><span id="line-481">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">482</span><span id="line-482">      admin.flush(tableName);</span>
+<span class="source-line-no">483</span><span id="line-483">      // wait flush is finished</span>
+<span class="source-line-no">484</span><span id="line-484">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">485</span><span id="line-485">        try {</span>
+<span class="source-line-no">486</span><span id="line-486">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
+<span class="source-line-no">487</span><span id="line-487">          for (RegionInfo region : regions) {</span>
+<span class="source-line-no">488</span><span id="line-488">            Path regionDir = new Path(tableDir, region.getEncodedName());</span>
+<span class="source-line-no">489</span><span id="line-489">            for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
+<span class="source-line-no">490</span><span id="line-490">              for (FileStatus fs : fs.listStatus(familyDir)) {</span>
+<span class="source-line-no">491</span><span id="line-491">                if (!fs.getPath().getName().equals(".filelist")) {</span>
+<span class="source-line-no">492</span><span id="line-492">                  return true;</span>
+<span class="source-line-no">493</span><span id="line-493">                }</span>
+<span class="source-line-no">494</span><span id="line-494">              }</span>
+<span class="source-line-no">495</span><span id="line-495">              return false;</span>
+<span class="source-line-no">496</span><span id="line-496">            }</span>
+<span class="source-line-no">497</span><span id="line-497">          }</span>
+<span class="source-line-no">498</span><span id="line-498">          return true;</span>
+<span class="source-line-no">499</span><span id="line-499">        } catch (IOException e) {</span>
+<span class="source-line-no">500</span><span id="line-500">          LOG.warn("Failed check if flush is finished", e);</span>
+<span class="source-line-no">501</span><span id="line-501">          return false;</span>
+<span class="source-line-no">502</span><span id="line-502">        }</span>
+<span class="source-line-no">503</span><span id="line-503">      });</span>
+<span class="source-line-no">504</span><span id="line-504">      // merge 2 regions</span>
+<span class="source-line-no">505</span><span id="line-505">      admin.compactionSwitch(false, serverList);</span>
+<span class="source-line-no">506</span><span id="line-506">      admin.mergeRegionsAsync(region0.getEncodedNameAsBytes(), region1.getEncodedNameAsBytes(),</span>
+<span class="source-line-no">507</span><span id="line-507">        true);</span>
+<span class="source-line-no">508</span><span id="line-508">      UTIL.waitFor(timeout, () -&gt; admin.getRegions(tableName).size() == 2);</span>
+<span class="source-line-no">509</span><span id="line-509">      List&lt;RegionInfo&gt; mergedRegions = admin.getRegions(tableName);</span>
+<span class="source-line-no">510</span><span id="line-510">      RegionInfo mergedRegion =</span>
+<span class="source-line-no">511</span><span id="line-511">        mergedRegions.get(0).getEncodedName().equals(region2.getEncodedName())</span>
+<span class="source-line-no">512</span><span id="line-512">          ? mergedRegions.get(1)</span>
+<span class="source-line-no">513</span><span id="line-513">          : mergedRegions.get(0);</span>
+<span class="source-line-no">514</span><span id="line-514">      // snapshot</span>
+<span class="source-line-no">515</span><span id="line-515">      admin.snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">516</span><span id="line-516">      assertEquals(1, admin.listSnapshots().size());</span>
+<span class="source-line-no">517</span><span id="line-517">      // major compact</span>
+<span class="source-line-no">518</span><span id="line-518">      admin.compactionSwitch(true, serverList);</span>
+<span class="source-line-no">519</span><span id="line-519">      admin.majorCompactRegion(mergedRegion.getRegionName());</span>
+<span class="source-line-no">520</span><span id="line-520">      // wait until merged region has no reference</span>
+<span class="source-line-no">521</span><span id="line-521">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">522</span><span id="line-522">        try {</span>
+<span class="source-line-no">523</span><span id="line-523">          for (RegionServerThread regionServerThread : UTIL.getMiniHBaseCluster()</span>
+<span class="source-line-no">524</span><span id="line-524">            .getRegionServerThreads()) {</span>
+<span class="source-line-no">525</span><span id="line-525">            HRegionServer regionServer = regionServerThread.getRegionServer();</span>
+<span class="source-line-no">526</span><span id="line-526">            for (HRegion subRegion : regionServer.getRegions(tableName)) {</span>
+<span class="source-line-no">527</span><span id="line-527">              if (</span>
+<span class="source-line-no">528</span><span id="line-528">                subRegion.getRegionInfo().getEncodedName().equals(mergedRegion.getEncodedName())</span>
+<span class="source-line-no">529</span><span id="line-529">              ) {</span>
+<span class="source-line-no">530</span><span id="line-530">                regionServer.getCompactedHFilesDischarger().chore();</span>
+<span class="source-line-no">531</span><span id="line-531">              }</span>
+<span class="source-line-no">532</span><span id="line-532">            }</span>
+<span class="source-line-no">533</span><span id="line-533">          }</span>
 <span class="source-line-no">534</span><span id="line-534">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
-<span class="source-line-no">535</span><span id="line-535">          for (FileStatus fileStatus : fs.listStatus(tableDir)) {</span>
-<span class="source-line-no">536</span><span id="line-536">            String name = fileStatus.getPath().getName();</span>
-<span class="source-line-no">537</span><span id="line-537">            if (name.equals(region0.getEncodedName()) || name.equals(region1.getEncodedName())) {</span>
-<span class="source-line-no">538</span><span id="line-538">              return false;</span>
-<span class="source-line-no">539</span><span id="line-539">            }</span>
-<span class="source-line-no">540</span><span id="line-540">          }</span>
-<span class="source-line-no">541</span><span id="line-541">          return true;</span>
-<span class="source-line-no">542</span><span id="line-542">        } catch (IOException e) {</span>
-<span class="source-line-no">543</span><span id="line-543">          LOG.warn("Check if parent regions are archived error", e);</span>
-<span class="source-line-no">544</span><span id="line-544">          return false;</span>
-<span class="source-line-no">545</span><span id="line-545">        }</span>
-<span class="source-line-no">546</span><span id="line-546">      });</span>
-<span class="source-line-no">547</span><span id="line-547">      // set file modify time and then run cleaner</span>
-<span class="source-line-no">548</span><span id="line-548">      long time = EnvironmentEdgeManager.currentTime() - TimeToLiveHFileCleaner.DEFAULT_TTL * 1000;</span>
-<span class="source-line-no">549</span><span id="line-549">      traverseAndSetFileTime(HFileArchiveUtil.getArchivePath(conf), time);</span>
-<span class="source-line-no">550</span><span id="line-550">      UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().triggerCleanerNow().get();</span>
-<span class="source-line-no">551</span><span id="line-551">      // scan snapshot</span>
-<span class="source-line-no">552</span><span id="line-552">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">553</span><span id="line-553">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">554</span><span id="line-554">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">555</span><span id="line-555">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">556</span><span id="line-556">      }</span>
-<span class="source-line-no">557</span><span id="line-557">    } catch (Exception e) {</span>
-<span class="source-line-no">558</span><span id="line-558">      LOG.error("scan snapshot error", e);</span>
-<span class="source-line-no">559</span><span id="line-559">      fail("Should not throw Exception: " + e.getMessage());</span>
-<span class="source-line-no">560</span><span id="line-560">    }</span>
-<span class="source-line-no">561</span><span id="line-561">  }</span>
-<span class="source-line-no">562</span><span id="line-562"></span>
-<span class="source-line-no">563</span><span id="line-563">  @Test</span>
-<span class="source-line-no">564</span><span id="line-564">  public void testDeleteTableWithMergedRegions() throws Exception {</span>
-<span class="source-line-no">565</span><span id="line-565">    final TableName tableName = TableName.valueOf(this.methodName);</span>
-<span class="source-line-no">566</span><span id="line-566">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
-<span class="source-line-no">567</span><span id="line-567">    Configuration conf = UTIL.getConfiguration();</span>
-<span class="source-line-no">568</span><span id="line-568">    try (Admin admin = UTIL.getConnection().getAdmin()) {</span>
-<span class="source-line-no">569</span><span id="line-569">      // disable compaction</span>
-<span class="source-line-no">570</span><span id="line-570">      admin.compactionSwitch(false,</span>
-<span class="source-line-no">571</span><span id="line-571">        admin.getRegionServers().stream().map(s -&gt; s.getServerName()).collect(Collectors.toList()));</span>
-<span class="source-line-no">572</span><span id="line-572">      // create table</span>
-<span class="source-line-no">573</span><span id="line-573">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
-<span class="source-line-no">574</span><span id="line-574">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">575</span><span id="line-575">      assertEquals(3, regions.size());</span>
-<span class="source-line-no">576</span><span id="line-576">      // write some data</span>
-<span class="source-line-no">577</span><span id="line-577">      UTIL.loadTable(table, FAMILIES);</span>
-<span class="source-line-no">578</span><span id="line-578">      // merge region</span>
-<span class="source-line-no">579</span><span id="line-579">      admin.mergeRegionsAsync(new byte[][] { regions.get(0).getEncodedNameAsBytes(),</span>
-<span class="source-line-no">580</span><span id="line-580">        regions.get(1).getEncodedNameAsBytes() }, false).get();</span>
-<span class="source-line-no">581</span><span id="line-581">      regions = admin.getRegions(tableName);</span>
-<span class="source-line-no">582</span><span id="line-582">      assertEquals(2, regions.size());</span>
-<span class="source-line-no">583</span><span id="line-583">      // snapshot</span>
-<span class="source-line-no">584</span><span id="line-584">      admin.snapshot(snapshotName, tableName);</span>
-<span class="source-line-no">585</span><span id="line-585">      // verify snapshot</span>
-<span class="source-line-no">586</span><span id="line-586">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">587</span><span id="line-587">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">588</span><span id="line-588">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">589</span><span id="line-589">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">590</span><span id="line-590">      }</span>
-<span class="source-line-no">591</span><span id="line-591">      // drop table</span>
-<span class="source-line-no">592</span><span id="line-592">      admin.disableTable(tableName);</span>
-<span class="source-line-no">593</span><span id="line-593">      admin.deleteTable(tableName);</span>
-<span class="source-line-no">594</span><span id="line-594">      // verify snapshot</span>
-<span class="source-line-no">595</span><span id="line-595">      try (TableSnapshotScanner scanner =</span>
-<span class="source-line-no">596</span><span id="line-596">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
-<span class="source-line-no">597</span><span id="line-597">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
-<span class="source-line-no">598</span><span id="line-598">        verifyScanner(scanner, bbb, yyy);</span>
-<span class="source-line-no">599</span><span id="line-599">      }</span>
-<span class="source-line-no">600</span><span id="line-600">    }</span>
-<span class="source-line-no">601</span><span id="line-601">  }</span>
-<span class="source-line-no">602</span><span id="line-602"></span>
-<span class="source-line-no">603</span><span id="line-603">  private void traverseAndSetFileTime(Path path, long time) throws IOException {</span>
-<span class="source-line-no">604</span><span id="line-604">    fs.setTimes(path, time, -1);</span>
-<span class="source-line-no">605</span><span id="line-605">    if (fs.isDirectory(path)) {</span>
-<span class="source-line-no">606</span><span id="line-606">      List&lt;FileStatus&gt; allPaths = Arrays.asList(fs.listStatus(path));</span>
-<span class="source-line-no">607</span><span id="line-607">      List&lt;FileStatus&gt; subDirs =</span>
-<span class="source-line-no">608</span><span id="line-608">        allPaths.stream().filter(FileStatus::isDirectory).collect(Collectors.toList());</span>
-<span class="source-line-no">609</span><span id="line-609">      List&lt;FileStatus&gt; files =</span>
-<span class="source-line-no">610</span><span id="line-610">        allPaths.stream().filter(FileStatus::isFile).collect(Collectors.toList());</span>
-<span class="source-line-no">611</span><span id="line-611">      for (FileStatus subDir : subDirs) {</span>
-<span class="source-line-no">612</span><span id="line-612">        traverseAndSetFileTime(subDir.getPath(), time);</span>
-<span class="source-line-no">613</span><span id="line-613">      }</span>
-<span class="source-line-no">614</span><span id="line-614">      for (FileStatus file : files) {</span>
-<span class="source-line-no">615</span><span id="line-615">        fs.setTimes(file.getPath(), time, -1);</span>
+<span class="source-line-no">535</span><span id="line-535">          HRegionFileSystem regionFs = HRegionFileSystem</span>
+<span class="source-line-no">536</span><span id="line-536">            .openRegionFromFileSystem(UTIL.getConfiguration(), fs, tableDir, mergedRegion, true);</span>
+<span class="source-line-no">537</span><span id="line-537">          boolean references = false;</span>
+<span class="source-line-no">538</span><span id="line-538">          Path regionDir = new Path(tableDir, mergedRegion.getEncodedName());</span>
+<span class="source-line-no">539</span><span id="line-539">          for (Path familyDir : FSUtils.getFamilyDirs(fs, regionDir)) {</span>
+<span class="source-line-no">540</span><span id="line-540">            StoreContext storeContext = StoreContext.getBuilder()</span>
+<span class="source-line-no">541</span><span id="line-541">              .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.of(familyDir.getName()))</span>
+<span class="source-line-no">542</span><span id="line-542">              .withRegionFileSystem(regionFs).withFamilyStoreDirectoryPath(familyDir).build();</span>
+<span class="source-line-no">543</span><span id="line-543">            StoreFileTracker sft =</span>
+<span class="source-line-no">544</span><span id="line-544">              StoreFileTrackerFactory.create(UTIL.getConfiguration(), false, storeContext);</span>
+<span class="source-line-no">545</span><span id="line-545">            references = references || sft.hasReferences();</span>
+<span class="source-line-no">546</span><span id="line-546">            if (references) {</span>
+<span class="source-line-no">547</span><span id="line-547">              break;</span>
+<span class="source-line-no">548</span><span id="line-548">            }</span>
+<span class="source-line-no">549</span><span id="line-549">          }</span>
+<span class="source-line-no">550</span><span id="line-550">          return !references;</span>
+<span class="source-line-no">551</span><span id="line-551">        } catch (IOException e) {</span>
+<span class="source-line-no">552</span><span id="line-552">          LOG.warn("Failed check merged region has no reference", e);</span>
+<span class="source-line-no">553</span><span id="line-553">          return false;</span>
+<span class="source-line-no">554</span><span id="line-554">        }</span>
+<span class="source-line-no">555</span><span id="line-555">      });</span>
+<span class="source-line-no">556</span><span id="line-556">      // run catalog janitor to clean and wait for parent regions are archived</span>
+<span class="source-line-no">557</span><span id="line-557">      UTIL.getMiniHBaseCluster().getMaster().getCatalogJanitor().choreForTesting();</span>
+<span class="source-line-no">558</span><span id="line-558">      UTIL.waitFor(timeout, () -&gt; {</span>
+<span class="source-line-no">559</span><span id="line-559">        try {</span>
+<span class="source-line-no">560</span><span id="line-560">          Path tableDir = CommonFSUtils.getTableDir(rootDir, tableName);</span>
+<span class="source-line-no">561</span><span id="line-561">          for (FileStatus fileStatus : fs.listStatus(tableDir)) {</span>
+<span class="source-line-no">562</span><span id="line-562">            String name = fileStatus.getPath().getName();</span>
+<span class="source-line-no">563</span><span id="line-563">            if (name.equals(region0.getEncodedName()) || name.equals(region1.getEncodedName())) {</span>
+<span class="source-line-no">564</span><span id="line-564">              return false;</span>
+<span class="source-line-no">565</span><span id="line-565">            }</span>
+<span class="source-line-no">566</span><span id="line-566">          }</span>
+<span class="source-line-no">567</span><span id="line-567">          return true;</span>
+<span class="source-line-no">568</span><span id="line-568">        } catch (IOException e) {</span>
+<span class="source-line-no">569</span><span id="line-569">          LOG.warn("Check if parent regions are archived error", e);</span>
+<span class="source-line-no">570</span><span id="line-570">          return false;</span>
+<span class="source-line-no">571</span><span id="line-571">        }</span>
+<span class="source-line-no">572</span><span id="line-572">      });</span>
+<span class="source-line-no">573</span><span id="line-573">      // set file modify time and then run cleaner</span>
+<span class="source-line-no">574</span><span id="line-574">      long time = EnvironmentEdgeManager.currentTime() - TimeToLiveHFileCleaner.DEFAULT_TTL * 1000;</span>
+<span class="source-line-no">575</span><span id="line-575">      traverseAndSetFileTime(HFileArchiveUtil.getArchivePath(conf), time);</span>
+<span class="source-line-no">576</span><span id="line-576">      UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().triggerCleanerNow().get();</span>
+<span class="source-line-no">577</span><span id="line-577">      // scan snapshot</span>
+<span class="source-line-no">578</span><span id="line-578">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">579</span><span id="line-579">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">580</span><span id="line-580">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">581</span><span id="line-581">        verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">582</span><span id="line-582">      }</span>
+<span class="source-line-no">583</span><span id="line-583">    } catch (Exception e) {</span>
+<span class="source-line-no">584</span><span id="line-584">      LOG.error("scan snapshot error", e);</span>
+<span class="source-line-no">585</span><span id="line-585">      fail("Should not throw Exception: " + e.getMessage());</span>
+<span class="source-line-no">586</span><span id="line-586">    }</span>
+<span class="source-line-no">587</span><span id="line-587">  }</span>
+<span class="source-line-no">588</span><span id="line-588"></span>
+<span class="source-line-no">589</span><span id="line-589">  @Test</span>
+<span class="source-line-no">590</span><span id="line-590">  public void testDeleteTableWithMergedRegions() throws Exception {</span>
+<span class="source-line-no">591</span><span id="line-591">    final TableName tableName = TableName.valueOf(this.methodName);</span>
+<span class="source-line-no">592</span><span id="line-592">    String snapshotName = tableName.getNameAsString() + "_snapshot";</span>
+<span class="source-line-no">593</span><span id="line-593">    Configuration conf = UTIL.getConfiguration();</span>
+<span class="source-line-no">594</span><span id="line-594">    try (Admin admin = UTIL.getConnection().getAdmin()) {</span>
+<span class="source-line-no">595</span><span id="line-595">      // disable compaction</span>
+<span class="source-line-no">596</span><span id="line-596">      admin.compactionSwitch(false,</span>
+<span class="source-line-no">597</span><span id="line-597">        admin.getRegionServers().stream().map(s -&gt; s.getServerName()).collect(Collectors.toList()));</span>
+<span class="source-line-no">598</span><span id="line-598">      // create table</span>
+<span class="source-line-no">599</span><span id="line-599">      Table table = UTIL.createTable(tableName, FAMILIES, 1, bbb, yyy, 3);</span>
+<span class="source-line-no">600</span><span id="line-600">      List&lt;RegionInfo&gt; regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">601</span><span id="line-601">      assertEquals(3, regions.size());</span>
+<span class="source-line-no">602</span><span id="line-602">      // write some data</span>
+<span class="source-line-no">603</span><span id="line-603">      UTIL.loadTable(table, FAMILIES);</span>
+<span class="source-line-no">604</span><span id="line-604">      // merge region</span>
+<span class="source-line-no">605</span><span id="line-605">      admin.mergeRegionsAsync(new byte[][] { regions.get(0).getEncodedNameAsBytes(),</span>
+<span class="source-line-no">606</span><span id="line-606">        regions.get(1).getEncodedNameAsBytes() }, false).get();</span>
+<span class="source-line-no">607</span><span id="line-607">      regions = admin.getRegions(tableName);</span>
+<span class="source-line-no">608</span><span id="line-608">      assertEquals(2, regions.size());</span>
+<span class="source-line-no">609</span><span id="line-609">      // snapshot</span>
+<span class="source-line-no">610</span><span id="line-610">      admin.snapshot(snapshotName, tableName);</span>
+<span class="source-line-no">611</span><span id="line-611">      // verify snapshot</span>
+<span class="source-line-no">612</span><span id="line-612">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">613</span><span id="line-613">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">614</span><span id="line-614">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">615</span><span id="line-615">        verifyScanner(scanner, bbb, yyy);</span>
 <span class="source-line-no">616</span><span id="line-616">      }</span>
-<span class="source-line-no">617</span><span id="line-617">    }</span>
-<span class="source-line-no">618</span><span id="line-618">  }</span>
-<span class="source-line-no">619</span><span id="line-619">}</span>
+<span class="source-line-no">617</span><span id="line-617">      // drop table</span>
+<span class="source-line-no">618</span><span id="line-618">      admin.disableTable(tableName);</span>
+<span class="source-line-no">619</span><span id="line-619">      admin.deleteTable(tableName);</span>
+<span class="source-line-no">620</span><span id="line-620">      // verify snapshot</span>
+<span class="source-line-no">621</span><span id="line-621">      try (TableSnapshotScanner scanner =</span>
+<span class="source-line-no">622</span><span id="line-622">        new TableSnapshotScanner(conf, UTIL.getDataTestDirOnTestFS(snapshotName), snapshotName,</span>
+<span class="source-line-no">623</span><span id="line-623">          new Scan().withStartRow(bbb).withStopRow(yyy))) {</span>
+<span class="source-line-no">624</span><span id="line-624">        verifyScanner(scanner, bbb, yyy);</span>
+<span class="source-line-no">625</span><span id="line-625">      }</span>
+<span class="source-line-no">626</span><span id="line-626">    }</span>
+<span class="source-line-no">627</span><span id="line-627">  }</span>
+<span class="source-line-no">628</span><span id="line-628"></span>
+<span class="source-line-no">629</span><span id="line-629">  private void traverseAndSetFileTime(Path path, long time) throws IOException {</span>
+<span class="source-line-no">630</span><span id="line-630">    fs.setTimes(path, time, -1);</span>
+<span class="source-line-no">631</span><span id="line-631">    if (fs.isDirectory(path)) {</span>
+<span class="source-line-no">632</span><span id="line-632">      List&lt;FileStatus&gt; allPaths = Arrays.asList(fs.listStatus(path));</span>
+<span class="source-line-no">633</span><span id="line-633">      List&lt;FileStatus&gt; subDirs =</span>
+<span class="source-line-no">634</span><span id="line-634">        allPaths.stream().filter(FileStatus::isDirectory).collect(Collectors.toList());</span>
+<span class="source-line-no">635</span><span id="line-635">      List&lt;FileStatus&gt; files =</span>
+<span class="source-line-no">636</span><span id="line-636">        allPaths.stream().filter(FileStatus::isFile).collect(Collectors.toList());</span>
+<span class="source-line-no">637</span><span id="line-637">      for (FileStatus subDir : subDirs) {</span>
+<span class="source-line-no">638</span><span id="line-638">        traverseAndSetFileTime(subDir.getPath(), time);</span>
+<span class="source-line-no">639</span><span id="line-639">      }</span>
+<span class="source-line-no">640</span><span id="line-640">      for (FileStatus file : files) {</span>
+<span class="source-line-no">641</span><span id="line-641">        fs.setTimes(file.getPath(), time, -1);</span>
+<span class="source-line-no">642</span><span id="line-642">      }</span>
+<span class="source-line-no">643</span><span id="line-643">    }</span>
+<span class="source-line-no">644</span><span id="line-644">  }</span>
+<span class="source-line-no">645</span><span id="line-645">}</span>
 
 
 
diff --git a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.AssignmentManagerForTest.html b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.AssignmentManagerForTest.html
index 14270af61a4..adb586288f0 100644
--- a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.AssignmentManagerForTest.html
+++ b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.AssignmentManagerForTest.html
@@ -146,54 +146,59 @@
 <span class="source-line-no">133</span><span id="line-133">  @BeforeEach</span>
 <span class="source-line-no">134</span><span id="line-134">  public void setUp() throws IOException {</span>
 <span class="source-line-no">135</span><span id="line-135">    UTIL.ensureSomeNonStoppedRegionServersAvailable(2);</span>
-<span class="source-line-no">136</span><span id="line-136">  }</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
-<span class="source-line-no">139</span><span id="line-139">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
-<span class="source-line-no">140</span><span id="line-140">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
-<span class="source-line-no">141</span><span id="line-141">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
-<span class="source-line-no">142</span><span id="line-142">  }</span>
-<span class="source-line-no">143</span><span id="line-143"></span>
-<span class="source-line-no">144</span><span id="line-144">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
-<span class="source-line-no">145</span><span id="line-145">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
-<span class="source-line-no">146</span><span id="line-146"></span>
-<span class="source-line-no">147</span><span id="line-147">      @Override</span>
-<span class="source-line-no">148</span><span id="line-148">      public boolean matches(Object item) {</span>
-<span class="source-line-no">149</span><span id="line-149">        if (!(item instanceof Procedure)) {</span>
-<span class="source-line-no">150</span><span id="line-150">          return false;</span>
-<span class="source-line-no">151</span><span id="line-151">        }</span>
-<span class="source-line-no">152</span><span id="line-152">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
-<span class="source-line-no">153</span><span id="line-153">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
-<span class="source-line-no">154</span><span id="line-154">      }</span>
-<span class="source-line-no">155</span><span id="line-155"></span>
-<span class="source-line-no">156</span><span id="line-156">      @Override</span>
-<span class="source-line-no">157</span><span id="line-157">      public void describeTo(Description description) {</span>
-<span class="source-line-no">158</span><span id="line-158">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">136</span><span id="line-136">    // Surefire reruns failed tests in the same JVM without rerunning @BeforeAll, so reset the</span>
+<span class="source-line-no">137</span><span id="line-137">    // fault injection state before each attempt.</span>
+<span class="source-line-no">138</span><span id="line-138">    INJECTED.set(false);</span>
+<span class="source-line-no">139</span><span id="line-139">    ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdateInRollback(</span>
+<span class="source-line-no">140</span><span id="line-140">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(), false);</span>
+<span class="source-line-no">141</span><span id="line-141">  }</span>
+<span class="source-line-no">142</span><span id="line-142"></span>
+<span class="source-line-no">143</span><span id="line-143">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
+<span class="source-line-no">144</span><span id="line-144">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
+<span class="source-line-no">145</span><span id="line-145">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
+<span class="source-line-no">146</span><span id="line-146">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
+<span class="source-line-no">147</span><span id="line-147">  }</span>
+<span class="source-line-no">148</span><span id="line-148"></span>
+<span class="source-line-no">149</span><span id="line-149">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
+<span class="source-line-no">150</span><span id="line-150">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
+<span class="source-line-no">151</span><span id="line-151"></span>
+<span class="source-line-no">152</span><span id="line-152">      @Override</span>
+<span class="source-line-no">153</span><span id="line-153">      public boolean matches(Object item) {</span>
+<span class="source-line-no">154</span><span id="line-154">        if (!(item instanceof Procedure)) {</span>
+<span class="source-line-no">155</span><span id="line-155">          return false;</span>
+<span class="source-line-no">156</span><span id="line-156">        }</span>
+<span class="source-line-no">157</span><span id="line-157">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
+<span class="source-line-no">158</span><span id="line-158">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
 <span class="source-line-no">159</span><span id="line-159">      }</span>
-<span class="source-line-no">160</span><span id="line-160">    };</span>
-<span class="source-line-no">161</span><span id="line-161">  }</span>
-<span class="source-line-no">162</span><span id="line-162"></span>
-<span class="source-line-no">163</span><span id="line-163">  @Test</span>
-<span class="source-line-no">164</span><span id="line-164">  public void testFailAndRollback() throws Exception {</span>
-<span class="source-line-no">165</span><span id="line-165">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
-<span class="source-line-no">166</span><span id="line-166">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">167</span><span id="line-167">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
-<span class="source-line-no">168</span><span id="line-168">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">169</span><span id="line-169">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
-<span class="source-line-no">170</span><span id="line-170">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
-<span class="source-line-no">171</span><span id="line-171">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
-<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
-<span class="source-line-no">173</span><span id="line-173">    // make sure that finally we could successfully rollback the procedure</span>
-<span class="source-line-no">174</span><span id="line-174">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
-<span class="source-line-no">175</span><span id="line-175">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
-<span class="source-line-no">176</span><span id="line-176">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
-<span class="source-line-no">177</span><span id="line-177">    }</span>
-<span class="source-line-no">178</span><span id="line-178">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
-<span class="source-line-no">179</span><span id="line-179">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
-<span class="source-line-no">180</span><span id="line-180">    // make sure all sub procedures are cleaned up</span>
-<span class="source-line-no">181</span><span id="line-181">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
-<span class="source-line-no">182</span><span id="line-182">  }</span>
-<span class="source-line-no">183</span><span id="line-183">}</span>
+<span class="source-line-no">160</span><span id="line-160"></span>
+<span class="source-line-no">161</span><span id="line-161">      @Override</span>
+<span class="source-line-no">162</span><span id="line-162">      public void describeTo(Description description) {</span>
+<span class="source-line-no">163</span><span id="line-163">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">164</span><span id="line-164">      }</span>
+<span class="source-line-no">165</span><span id="line-165">    };</span>
+<span class="source-line-no">166</span><span id="line-166">  }</span>
+<span class="source-line-no">167</span><span id="line-167"></span>
+<span class="source-line-no">168</span><span id="line-168">  @Test</span>
+<span class="source-line-no">169</span><span id="line-169">  public void testFailAndRollback() throws Exception {</span>
+<span class="source-line-no">170</span><span id="line-170">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
+<span class="source-line-no">171</span><span id="line-171">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
+<span class="source-line-no">173</span><span id="line-173">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">174</span><span id="line-174">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
+<span class="source-line-no">175</span><span id="line-175">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
+<span class="source-line-no">176</span><span id="line-176">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
+<span class="source-line-no">177</span><span id="line-177">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
+<span class="source-line-no">178</span><span id="line-178">    // make sure that finally we could successfully rollback the procedure</span>
+<span class="source-line-no">179</span><span id="line-179">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
+<span class="source-line-no">180</span><span id="line-180">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
+<span class="source-line-no">181</span><span id="line-181">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
+<span class="source-line-no">182</span><span id="line-182">    }</span>
+<span class="source-line-no">183</span><span id="line-183">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
+<span class="source-line-no">184</span><span id="line-184">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
+<span class="source-line-no">185</span><span id="line-185">    // make sure all sub procedures are cleaned up</span>
+<span class="source-line-no">186</span><span id="line-186">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
+<span class="source-line-no">187</span><span id="line-187">  }</span>
+<span class="source-line-no">188</span><span id="line-188">}</span>
 
 
 
diff --git a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.HMasterForTest.html b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.HMasterForTest.html
index 6de9d95a1ea..5a1ae2b0896 100644
--- a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.HMasterForTest.html
+++ b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.HMasterForTest.html
@@ -146,54 +146,59 @@
 <span class="source-line-no">133</span><span id="line-133">  @BeforeEach</span>
 <span class="source-line-no">134</span><span id="line-134">  public void setUp() throws IOException {</span>
 <span class="source-line-no">135</span><span id="line-135">    UTIL.ensureSomeNonStoppedRegionServersAvailable(2);</span>
-<span class="source-line-no">136</span><span id="line-136">  }</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
-<span class="source-line-no">139</span><span id="line-139">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
-<span class="source-line-no">140</span><span id="line-140">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
-<span class="source-line-no">141</span><span id="line-141">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
-<span class="source-line-no">142</span><span id="line-142">  }</span>
-<span class="source-line-no">143</span><span id="line-143"></span>
-<span class="source-line-no">144</span><span id="line-144">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
-<span class="source-line-no">145</span><span id="line-145">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
-<span class="source-line-no">146</span><span id="line-146"></span>
-<span class="source-line-no">147</span><span id="line-147">      @Override</span>
-<span class="source-line-no">148</span><span id="line-148">      public boolean matches(Object item) {</span>
-<span class="source-line-no">149</span><span id="line-149">        if (!(item instanceof Procedure)) {</span>
-<span class="source-line-no">150</span><span id="line-150">          return false;</span>
-<span class="source-line-no">151</span><span id="line-151">        }</span>
-<span class="source-line-no">152</span><span id="line-152">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
-<span class="source-line-no">153</span><span id="line-153">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
-<span class="source-line-no">154</span><span id="line-154">      }</span>
-<span class="source-line-no">155</span><span id="line-155"></span>
-<span class="source-line-no">156</span><span id="line-156">      @Override</span>
-<span class="source-line-no">157</span><span id="line-157">      public void describeTo(Description description) {</span>
-<span class="source-line-no">158</span><span id="line-158">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">136</span><span id="line-136">    // Surefire reruns failed tests in the same JVM without rerunning @BeforeAll, so reset the</span>
+<span class="source-line-no">137</span><span id="line-137">    // fault injection state before each attempt.</span>
+<span class="source-line-no">138</span><span id="line-138">    INJECTED.set(false);</span>
+<span class="source-line-no">139</span><span id="line-139">    ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdateInRollback(</span>
+<span class="source-line-no">140</span><span id="line-140">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(), false);</span>
+<span class="source-line-no">141</span><span id="line-141">  }</span>
+<span class="source-line-no">142</span><span id="line-142"></span>
+<span class="source-line-no">143</span><span id="line-143">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
+<span class="source-line-no">144</span><span id="line-144">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
+<span class="source-line-no">145</span><span id="line-145">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
+<span class="source-line-no">146</span><span id="line-146">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
+<span class="source-line-no">147</span><span id="line-147">  }</span>
+<span class="source-line-no">148</span><span id="line-148"></span>
+<span class="source-line-no">149</span><span id="line-149">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
+<span class="source-line-no">150</span><span id="line-150">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
+<span class="source-line-no">151</span><span id="line-151"></span>
+<span class="source-line-no">152</span><span id="line-152">      @Override</span>
+<span class="source-line-no">153</span><span id="line-153">      public boolean matches(Object item) {</span>
+<span class="source-line-no">154</span><span id="line-154">        if (!(item instanceof Procedure)) {</span>
+<span class="source-line-no">155</span><span id="line-155">          return false;</span>
+<span class="source-line-no">156</span><span id="line-156">        }</span>
+<span class="source-line-no">157</span><span id="line-157">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
+<span class="source-line-no">158</span><span id="line-158">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
 <span class="source-line-no">159</span><span id="line-159">      }</span>
-<span class="source-line-no">160</span><span id="line-160">    };</span>
-<span class="source-line-no">161</span><span id="line-161">  }</span>
-<span class="source-line-no">162</span><span id="line-162"></span>
-<span class="source-line-no">163</span><span id="line-163">  @Test</span>
-<span class="source-line-no">164</span><span id="line-164">  public void testFailAndRollback() throws Exception {</span>
-<span class="source-line-no">165</span><span id="line-165">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
-<span class="source-line-no">166</span><span id="line-166">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">167</span><span id="line-167">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
-<span class="source-line-no">168</span><span id="line-168">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">169</span><span id="line-169">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
-<span class="source-line-no">170</span><span id="line-170">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
-<span class="source-line-no">171</span><span id="line-171">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
-<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
-<span class="source-line-no">173</span><span id="line-173">    // make sure that finally we could successfully rollback the procedure</span>
-<span class="source-line-no">174</span><span id="line-174">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
-<span class="source-line-no">175</span><span id="line-175">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
-<span class="source-line-no">176</span><span id="line-176">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
-<span class="source-line-no">177</span><span id="line-177">    }</span>
-<span class="source-line-no">178</span><span id="line-178">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
-<span class="source-line-no">179</span><span id="line-179">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
-<span class="source-line-no">180</span><span id="line-180">    // make sure all sub procedures are cleaned up</span>
-<span class="source-line-no">181</span><span id="line-181">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
-<span class="source-line-no">182</span><span id="line-182">  }</span>
-<span class="source-line-no">183</span><span id="line-183">}</span>
+<span class="source-line-no">160</span><span id="line-160"></span>
+<span class="source-line-no">161</span><span id="line-161">      @Override</span>
+<span class="source-line-no">162</span><span id="line-162">      public void describeTo(Description description) {</span>
+<span class="source-line-no">163</span><span id="line-163">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">164</span><span id="line-164">      }</span>
+<span class="source-line-no">165</span><span id="line-165">    };</span>
+<span class="source-line-no">166</span><span id="line-166">  }</span>
+<span class="source-line-no">167</span><span id="line-167"></span>
+<span class="source-line-no">168</span><span id="line-168">  @Test</span>
+<span class="source-line-no">169</span><span id="line-169">  public void testFailAndRollback() throws Exception {</span>
+<span class="source-line-no">170</span><span id="line-170">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
+<span class="source-line-no">171</span><span id="line-171">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
+<span class="source-line-no">173</span><span id="line-173">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">174</span><span id="line-174">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
+<span class="source-line-no">175</span><span id="line-175">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
+<span class="source-line-no">176</span><span id="line-176">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
+<span class="source-line-no">177</span><span id="line-177">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
+<span class="source-line-no">178</span><span id="line-178">    // make sure that finally we could successfully rollback the procedure</span>
+<span class="source-line-no">179</span><span id="line-179">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
+<span class="source-line-no">180</span><span id="line-180">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
+<span class="source-line-no">181</span><span id="line-181">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
+<span class="source-line-no">182</span><span id="line-182">    }</span>
+<span class="source-line-no">183</span><span id="line-183">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
+<span class="source-line-no">184</span><span id="line-184">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
+<span class="source-line-no">185</span><span id="line-185">    // make sure all sub procedures are cleaned up</span>
+<span class="source-line-no">186</span><span id="line-186">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
+<span class="source-line-no">187</span><span id="line-187">  }</span>
+<span class="source-line-no">188</span><span id="line-188">}</span>
 
 
 
diff --git a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
index fabe4c735c5..82053529f6b 100644
--- a/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
+++ b/testdevapidocs/src-html/org/apache/hadoop/hbase/master/assignment/TestRollbackSCP.html
@@ -146,54 +146,59 @@
 <span class="source-line-no">133</span><span id="line-133">  @BeforeEach</span>
 <span class="source-line-no">134</span><span id="line-134">  public void setUp() throws IOException {</span>
 <span class="source-line-no">135</span><span id="line-135">    UTIL.ensureSomeNonStoppedRegionServersAvailable(2);</span>
-<span class="source-line-no">136</span><span id="line-136">  }</span>
-<span class="source-line-no">137</span><span id="line-137"></span>
-<span class="source-line-no">138</span><span id="line-138">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
-<span class="source-line-no">139</span><span id="line-139">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
-<span class="source-line-no">140</span><span id="line-140">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
-<span class="source-line-no">141</span><span id="line-141">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
-<span class="source-line-no">142</span><span id="line-142">  }</span>
-<span class="source-line-no">143</span><span id="line-143"></span>
-<span class="source-line-no">144</span><span id="line-144">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
-<span class="source-line-no">145</span><span id="line-145">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
-<span class="source-line-no">146</span><span id="line-146"></span>
-<span class="source-line-no">147</span><span id="line-147">      @Override</span>
-<span class="source-line-no">148</span><span id="line-148">      public boolean matches(Object item) {</span>
-<span class="source-line-no">149</span><span id="line-149">        if (!(item instanceof Procedure)) {</span>
-<span class="source-line-no">150</span><span id="line-150">          return false;</span>
-<span class="source-line-no">151</span><span id="line-151">        }</span>
-<span class="source-line-no">152</span><span id="line-152">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
-<span class="source-line-no">153</span><span id="line-153">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
-<span class="source-line-no">154</span><span id="line-154">      }</span>
-<span class="source-line-no">155</span><span id="line-155"></span>
-<span class="source-line-no">156</span><span id="line-156">      @Override</span>
-<span class="source-line-no">157</span><span id="line-157">      public void describeTo(Description description) {</span>
-<span class="source-line-no">158</span><span id="line-158">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">136</span><span id="line-136">    // Surefire reruns failed tests in the same JVM without rerunning @BeforeAll, so reset the</span>
+<span class="source-line-no">137</span><span id="line-137">    // fault injection state before each attempt.</span>
+<span class="source-line-no">138</span><span id="line-138">    INJECTED.set(false);</span>
+<span class="source-line-no">139</span><span id="line-139">    ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdateInRollback(</span>
+<span class="source-line-no">140</span><span id="line-140">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(), false);</span>
+<span class="source-line-no">141</span><span id="line-141">  }</span>
+<span class="source-line-no">142</span><span id="line-142"></span>
+<span class="source-line-no">143</span><span id="line-143">  private ServerCrashProcedure getSCPForServer(ServerName serverName) throws IOException {</span>
+<span class="source-line-no">144</span><span id="line-144">    return UTIL.getMiniHBaseCluster().getMaster().getProcedures().stream()</span>
+<span class="source-line-no">145</span><span id="line-145">      .filter(p -&gt; p instanceof ServerCrashProcedure).map(p -&gt; (ServerCrashProcedure) p)</span>
+<span class="source-line-no">146</span><span id="line-146">      .filter(p -&gt; p.getServerName().equals(serverName)).findFirst().orElse(null);</span>
+<span class="source-line-no">147</span><span id="line-147">  }</span>
+<span class="source-line-no">148</span><span id="line-148"></span>
+<span class="source-line-no">149</span><span id="line-149">  private Matcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt; subProcOf(Procedure&lt;MasterProcedureEnv&gt; proc) {</span>
+<span class="source-line-no">150</span><span id="line-150">    return new BaseMatcher&lt;Procedure&lt;MasterProcedureEnv&gt;&gt;() {</span>
+<span class="source-line-no">151</span><span id="line-151"></span>
+<span class="source-line-no">152</span><span id="line-152">      @Override</span>
+<span class="source-line-no">153</span><span id="line-153">      public boolean matches(Object item) {</span>
+<span class="source-line-no">154</span><span id="line-154">        if (!(item instanceof Procedure)) {</span>
+<span class="source-line-no">155</span><span id="line-155">          return false;</span>
+<span class="source-line-no">156</span><span id="line-156">        }</span>
+<span class="source-line-no">157</span><span id="line-157">        Procedure&lt;?&gt; p = (Procedure&lt;?&gt;) item;</span>
+<span class="source-line-no">158</span><span id="line-158">        return p.hasParent() &amp;&amp; p.getRootProcId() == proc.getProcId();</span>
 <span class="source-line-no">159</span><span id="line-159">      }</span>
-<span class="source-line-no">160</span><span id="line-160">    };</span>
-<span class="source-line-no">161</span><span id="line-161">  }</span>
-<span class="source-line-no">162</span><span id="line-162"></span>
-<span class="source-line-no">163</span><span id="line-163">  @Test</span>
-<span class="source-line-no">164</span><span id="line-164">  public void testFailAndRollback() throws Exception {</span>
-<span class="source-line-no">165</span><span id="line-165">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
-<span class="source-line-no">166</span><span id="line-166">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">167</span><span id="line-167">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
-<span class="source-line-no">168</span><span id="line-168">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
-<span class="source-line-no">169</span><span id="line-169">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
-<span class="source-line-no">170</span><span id="line-170">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
-<span class="source-line-no">171</span><span id="line-171">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
-<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
-<span class="source-line-no">173</span><span id="line-173">    // make sure that finally we could successfully rollback the procedure</span>
-<span class="source-line-no">174</span><span id="line-174">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
-<span class="source-line-no">175</span><span id="line-175">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
-<span class="source-line-no">176</span><span id="line-176">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
-<span class="source-line-no">177</span><span id="line-177">    }</span>
-<span class="source-line-no">178</span><span id="line-178">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
-<span class="source-line-no">179</span><span id="line-179">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
-<span class="source-line-no">180</span><span id="line-180">    // make sure all sub procedures are cleaned up</span>
-<span class="source-line-no">181</span><span id="line-181">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
-<span class="source-line-no">182</span><span id="line-182">  }</span>
-<span class="source-line-no">183</span><span id="line-183">}</span>
+<span class="source-line-no">160</span><span id="line-160"></span>
+<span class="source-line-no">161</span><span id="line-161">      @Override</span>
+<span class="source-line-no">162</span><span id="line-162">      public void describeTo(Description description) {</span>
+<span class="source-line-no">163</span><span id="line-163">        description.appendText("sub procedure of(").appendValue(proc).appendText(")");</span>
+<span class="source-line-no">164</span><span id="line-164">      }</span>
+<span class="source-line-no">165</span><span id="line-165">    };</span>
+<span class="source-line-no">166</span><span id="line-166">  }</span>
+<span class="source-line-no">167</span><span id="line-167"></span>
+<span class="source-line-no">168</span><span id="line-168">  @Test</span>
+<span class="source-line-no">169</span><span id="line-169">  public void testFailAndRollback() throws Exception {</span>
+<span class="source-line-no">170</span><span id="line-170">    HRegionServer rsWithMeta = UTIL.getRSForFirstRegionInTable(TableName.META_TABLE_NAME);</span>
+<span class="source-line-no">171</span><span id="line-171">    UTIL.getMiniHBaseCluster().killRegionServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">172</span><span id="line-172">    UTIL.waitFor(15000, () -&gt; getSCPForServer(rsWithMeta.getServerName()) != null);</span>
+<span class="source-line-no">173</span><span id="line-173">    ServerCrashProcedure scp = getSCPForServer(rsWithMeta.getServerName());</span>
+<span class="source-line-no">174</span><span id="line-174">    ProcedureExecutor&lt;MasterProcedureEnv&gt; procExec =</span>
+<span class="source-line-no">175</span><span id="line-175">      UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor();</span>
+<span class="source-line-no">176</span><span id="line-176">    // wait for the procedure to stop, as we inject a code bug and also set kill before store update</span>
+<span class="source-line-no">177</span><span id="line-177">    UTIL.waitFor(30000, () -&gt; !procExec.isRunning());</span>
+<span class="source-line-no">178</span><span id="line-178">    // make sure that finally we could successfully rollback the procedure</span>
+<span class="source-line-no">179</span><span id="line-179">    while (scp.getState() != ProcedureState.FAILED || !procExec.isRunning()) {</span>
+<span class="source-line-no">180</span><span id="line-180">      MasterProcedureTestingUtility.restartMasterProcedureExecutor(procExec);</span>
+<span class="source-line-no">181</span><span id="line-181">      ProcedureTestingUtility.waitProcedure(procExec, scp);</span>
+<span class="source-line-no">182</span><span id="line-182">    }</span>
+<span class="source-line-no">183</span><span id="line-183">    assertEquals(scp.getState(), ProcedureState.FAILED);</span>
+<span class="source-line-no">184</span><span id="line-184">    assertThat(scp.getException().getMessage(), containsString("inject code bug"));</span>
+<span class="source-line-no">185</span><span id="line-185">    // make sure all sub procedures are cleaned up</span>
+<span class="source-line-no">186</span><span id="line-186">    assertThat(procExec.getProcedures(), everyItem(not(subProcOf(scp))));</span>
+<span class="source-line-no">187</span><span id="line-187">  }</span>
+<span class="source-line-no">188</span><span id="line-188">}</span>