private void testPrefetchWhenHFileLink(Consumer<Cacheable> test) throws Exception {
    cacheConf = new CacheConfig(conf, blockCache);
    HFileContext context = new HFileContextBuilder().withBlockSize(DATA_BLOCK_SIZE).build();
    Path testDir = TEST_UTIL.getDataTestDir("testPrefetchWhenHFileLink");
    final RegionInfo hri =
      RegionInfoBuilder.newBuilder(TableName.valueOf("testPrefetchWhenHFileLink")).build();
    // force temp data in hbase/target/test-data instead of /tmp/hbase-xxxx/
    Configuration testConf = new Configuration(this.conf);
    CommonFSUtils.setRootDir(testConf, testDir);
    HRegionFileSystem regionFs = HRegionFileSystem.createRegionOnFileSystem(testConf, fs,
      CommonFSUtils.getTableDir(testDir, hri.getTable()), hri);

    // Make a store file and write data to it.
    StoreFileWriter writer = new StoreFileWriter.Builder(conf, cacheConf, this.fs)
      .withFilePath(regionFs.createTempName()).withFileContext(context).build();
    TestHStoreFile.writeStoreFile(writer, Bytes.toBytes("testPrefetchWhenHFileLink"),
      Bytes.toBytes("testPrefetchWhenHFileLink"));

    Path storeFilePath = regionFs.commitStoreFile("cf", writer.getPath());
    final RegionInfo dstHri =
      RegionInfoBuilder.newBuilder(TableName.valueOf("testPrefetchWhenHFileLink")).build();
    HRegionFileSystem dstRegionFs = HRegionFileSystem.createRegionOnFileSystem(testConf, fs,
      CommonFSUtils.getTableDir(testDir, dstHri.getTable()), dstHri);
    Path dstPath = new Path(regionFs.getTableDir(), new Path(dstHri.getRegionNameAsString(), "cf"));
    StoreFileTracker sft = StoreFileTrackerFactory.create(testConf, false,
      StoreContext.getBuilder()
        .withFamilyStoreDirectoryPath(new Path(dstRegionFs.getRegionDir(), "cf"))
        .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.of("cf"))
        .withRegionFileSystem(dstRegionFs).build());
    sft.createHFileLink(hri.getTable(), hri.getEncodedName(), storeFilePath.getName(), true);
    Path linkFilePath =
      new Path(dstPath, HFileLink.createHFileLinkName(hri, storeFilePath.getName()));

    // Try to open store file from link
    StoreFileInfo storeFileInfo = sft.getStoreFileInfo(linkFilePath, true);
    HStoreFile hsf = new HStoreFile(storeFileInfo, BloomType.NONE, cacheConf);
    assertTrue(storeFileInfo.isLink());

    hsf.initReader();
    HFile.Reader reader = hsf.getReader().getHFileReader();
    while (!reader.prefetchComplete()) {
      // Sleep for a bit
      Thread.sleep(1000);
    }
    long offset = 0;
    while (offset < reader.getTrailer().getLoadOnOpenDataOffset()) {
      HFileBlock block = reader.readBlock(offset, -1, false, true, false, true, null, null, true);
      BlockCacheKey blockCacheKey = new BlockCacheKey(reader.getName(), offset);
      if (block.getBlockType() == BlockType.DATA) {
        test.accept(blockCache.getBlock(blockCacheKey, true, false, true));
      }
      offset += block.getOnDiskSizeWithHeader();
    }
  }
Read a storefile in the same manner as a scanner -- using non-positional reads and without
waiting for prefetch to complete.
hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestPrefetch.java