private void checkHalfHFile(final HRegionFileSystem regionFs, final HStoreFile f,
    StoreFileTracker sft) throws IOException {
    f.initReader();
    Cell midkey = f.getReader().midKey().get();
    KeyValue midKV = (KeyValue) midkey;
    // 1. test using the midRow as the splitKey, this test will generate two Reference files
    // in the children
    byte[] midRow = CellUtil.cloneRow(midKV);
    // Create top split.
    RegionInfo topHri =
      RegionInfoBuilder.newBuilder(regionFs.getRegionInfo().getTable()).setEndKey(SPLITKEY).build();
    Path topPath = splitStoreFile(regionFs, topHri, TEST_FAMILY, f, midRow, true, sft);
    // Create bottom split.
    RegionInfo bottomHri = RegionInfoBuilder.newBuilder(regionFs.getRegionInfo().getTable())
      .setStartKey(SPLITKEY).build();
    Path bottomPath = splitStoreFile(regionFs, bottomHri, TEST_FAMILY, f, midRow, false, sft);
    // Make readers on top and bottom.
    HStoreFile topF = new HStoreFile(this.fs, topPath, conf, cacheConf, BloomType.NONE, true, sft);
    topF.initReader();
    StoreFileReader top = topF.getReader();
    HStoreFile bottomF =
      new HStoreFile(this.fs, bottomPath, conf, cacheConf, BloomType.NONE, true, sft);
    bottomF.initReader();
    StoreFileReader bottom = bottomF.getReader();
    ByteBuffer previous = null;
    LOG.info("Midkey: " + midKV.toString());
    ByteBuffer bbMidkeyBytes = ByteBuffer.wrap(midKV.getKey());
    try {
      // Now make two HalfMapFiles and assert they can read the full backing
      // file, one from the top and the other from the bottom.
      // Test bottom half first.
      // Now test reading from the top.
      boolean first = true;
      ByteBuffer key = null;
      try (HFileScanner topScanner = top.getScanner(false, false, false)) {
        while (
          (!topScanner.isSeeked() && topScanner.seekTo())
            || (topScanner.isSeeked() && topScanner.next())
        ) {
          key = ByteBuffer.wrap(((KeyValue) topScanner.getKey()).getKey());

          if (
            (PrivateCellUtil.compare(topScanner.getReader().getComparator(), midKV, key.array(),
              key.arrayOffset(), key.limit())) > 0
          ) {
            fail("key=" + Bytes.toStringBinary(key) + " < midkey=" + midkey);
          }
          if (first) {
            first = false;
            LOG.info("First in top: " + Bytes.toString(Bytes.toBytes(key)));
          }
        }
      }
      LOG.info("Last in top: " + Bytes.toString(Bytes.toBytes(key)));

      first = true;
      try (HFileScanner bottomScanner = bottom.getScanner(false, false, false)) {
        while ((!bottomScanner.isSeeked() && bottomScanner.seekTo()) || bottomScanner.next()) {
          previous = ByteBuffer.wrap(((KeyValue) bottomScanner.getKey()).getKey());
          key = ByteBuffer.wrap(((KeyValue) bottomScanner.getKey()).getKey());
          if (first) {
            first = false;
            LOG.info("First in bottom: " + Bytes.toString(Bytes.toBytes(previous)));
          }
          assertTrue(key.compareTo(bbMidkeyBytes) < 0);
        }
        if (previous != null) {
          LOG.info("Last in bottom: " + Bytes.toString(Bytes.toBytes(previous)));
        }
      }
      // Remove references.
      regionFs.cleanupDaughterRegion(topHri);
      regionFs.cleanupDaughterRegion(bottomHri);

      // 2. test using a midkey which will generate one Reference file and one HFileLink file.
      // First, do a key that is < than first key. Ensure splits behave
      // properly.
      byte[] badmidkey = Bytes.toBytes("  .");
      assertTrue(fs.exists(f.getPath()));
      topPath = splitStoreFile(regionFs, topHri, TEST_FAMILY, f, badmidkey, true, sft);
      bottomPath = splitStoreFile(regionFs, bottomHri, TEST_FAMILY, f, badmidkey, false, sft);

      assertNull(bottomPath);

      topF = new HStoreFile(this.fs, topPath, conf, cacheConf, BloomType.NONE, true, sft);
      topF.initReader();
      top = topF.getReader();
      // Now read from the top.
      first = true;
      try (HFileScanner topScanner = top.getScanner(false, false, false)) {
        KeyValue.KeyOnlyKeyValue keyOnlyKV = new KeyValue.KeyOnlyKeyValue();
        while ((!topScanner.isSeeked() && topScanner.seekTo()) || topScanner.next()) {
          key = ByteBuffer.wrap(((KeyValue) topScanner.getKey()).getKey());
          keyOnlyKV.setKey(key.array(), 0 + key.arrayOffset(), key.limit());
          assertTrue(PrivateCellUtil.compare(topScanner.getReader().getComparator(), keyOnlyKV,
            badmidkey, 0, badmidkey.length) >= 0);
          if (first) {
            first = false;
            KeyValue keyKV = KeyValueUtil.createKeyValueFromKey(key);
            LOG.info("First top when key < bottom: " + keyKV);
            String tmp =
              Bytes.toString(keyKV.getRowArray(), keyKV.getRowOffset(), keyKV.getRowLength());
            for (int i = 0; i < tmp.length(); i++) {
              assertTrue(tmp.charAt(i) == 'a');
            }
          }
        }
        KeyValue keyKV = KeyValueUtil.createKeyValueFromKey(key);
        LOG.info("Last top when key < bottom: " + keyKV);
        String tmp =
          Bytes.toString(keyKV.getRowArray(), keyKV.getRowOffset(), keyKV.getRowLength());
        for (int i = 0; i < tmp.length(); i++) {
          assertTrue(tmp.charAt(i) == 'z');
        }
      }
      // Remove references.
      regionFs.cleanupDaughterRegion(topHri);
      regionFs.cleanupDaughterRegion(bottomHri);

      // Test when badkey is > than last key in file ('||' > 'zz').
      badmidkey = Bytes.toBytes("|||");
      topPath = splitStoreFile(regionFs, topHri, TEST_FAMILY, f, badmidkey, true, sft);
      bottomPath = splitStoreFile(regionFs, bottomHri, TEST_FAMILY, f, badmidkey, false, sft);
      assertNull(topPath);

      bottomF = new HStoreFile(this.fs, bottomPath, conf, cacheConf, BloomType.NONE, true, sft);
      bottomF.initReader();
      bottom = bottomF.getReader();
      first = true;
      try (HFileScanner bottomScanner = bottom.getScanner(false, false, false)) {
        while ((!bottomScanner.isSeeked() && bottomScanner.seekTo()) || bottomScanner.next()) {
          key = ByteBuffer.wrap(((KeyValue) bottomScanner.getKey()).getKey());
          if (first) {
            first = false;
            KeyValue keyKV = KeyValueUtil.createKeyValueFromKey(key);
            LOG.info("First bottom when key > top: " + keyKV);
            String tmp =
              Bytes.toString(keyKV.getRowArray(), keyKV.getRowOffset(), keyKV.getRowLength());
            for (int i = 0; i < tmp.length(); i++) {
              assertTrue(tmp.charAt(i) == 'a');
            }
          }
        }
        KeyValue keyKV = KeyValueUtil.createKeyValueFromKey(key);
        LOG.info("Last bottom when key > top: " + keyKV);
        String tmp =
          Bytes.toString(keyKV.getRowArray(), keyKV.getRowOffset(), keyKV.getRowLength());
        for (int i = 0; i < tmp.length(); i++) {
          assertTrue(Bytes.toString(keyKV.getRowArray(), keyKV.getRowOffset(), keyKV.getRowLength())
            .charAt(i) == 'z');
        }
      }
    } finally {
      if (top != null) {
        top.close(true); // evict since we are about to delete the file
      }
      if (bottom != null) {
        bottom.close(true); // evict since we are about to delete the file
      }
      fs.delete(f.getPath(), true);
    }
  }
This test creates an hfile and then the dir structures and files to verify that references to
hfilelinks (created by snapshot clones) can be properly interpreted.
hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHStoreFile.java