private boolean seekToPreviousRowWithHint() throws IOException {
    do {
      // Using our existing seek hint, set our next seek hint
      ExtendedCell firstKeyOfPreviousRow = PrivateCellUtil.createFirstOnRow(previousRow);
      seekBeforeAndSaveKeyToPreviousRow(firstKeyOfPreviousRow);

      // Reseek back to our initial seek hint (i.e. what we think is the start of the
      // previous row)
      if (!reseekAtOrAfter(firstKeyOfPreviousRow)) {
        return false;
      }

      // If after skipping newer Kvs, we're still in our seek hint row, then we're finished
      if (isStillAtSeekTargetAfterSkippingNewerKvs(firstKeyOfPreviousRow)) {
        return true;
      }

      // If the previousRow seek hint is missing, that means that we're at row after the first row
      // in the storefile. Use the without-hint seek path to process the final row
      if (previousRow == null) {
        return seekToPreviousRowWithoutHint(firstKeyOfPreviousRow);
      }

      // Otherwise, use the previousRow seek hint to continue traversing backwards
    } while (true);
  }
This variant of the {@link StoreFileScanner#seekToPreviousRow(ExtendedCell)} method requires
one seek and one reseek. This method maintains state in {@link StoreFileScanner#previousRow}
which only makes sense in the context of a sequential row-by-row reverse scan.
{@link StoreFileScanner#previousRow} should be reset if that is not the case. The reasoning for
why this method is faster than
{@link StoreFileScanner#seekToPreviousRowStateless(ExtendedCell)} is that seeks are slower as
they need to start from the beginning of the file, while reseeks go forward from the current
position.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileScanner.java