void pruneHardDeleteRecoveryRange() {
    StoreFindToken logFlushedTillToken = (StoreFindToken) startTokenSafeToPersist;
    if (logFlushedTillToken != null && !logFlushedTillToken.getType().equals(FindTokenType.Uninitialized)) {
      if (logFlushedTillToken.equals(endToken)) {
        hardDeleteRecoveryRange.clear();
      } else if (logFlushedTillToken.getStoreKey() != null) {
          /* Avoid pruning if the token is journal based as it is complicated and unnecessary. This is because, in the
             recovery range, keys are stored not offsets. It should be okay to not prune though, as there is no
             correctness issue. Additionally, since this token is journal based, it is highly likely that this token
             will soon become equal to endtoken, in which case we will prune everything (in the "if case" above).
             If the token is index based, safely prune off entries that have already been flushed in the log */
        hardDeleteRecoveryRange.pruneTill(logFlushedTillToken);
      }
    }
    if (hardDeleteRecoveryRange.getSize() > 0) {
      logger.trace("Pruned Hard delete recovery range : {} to {} with size {} for {}",
          hardDeleteRecoveryRange.items.get(0).blobReadOptions,
          hardDeleteRecoveryRange.items.get(hardDeleteRecoveryRange.getSize() - 1).blobReadOptions,
          hardDeleteRecoveryRange.getSize(), dataDir);
    } else {
      logger.trace("Hard delete recovery range is empty for {}", dataDir);
    }
  }
Prunes the hardDeleteRecoveryRange so that all the information for keys before startTokenSafeToPersist are
removed. This is safe as the hard deleted writes of those keys are guaranteed to have been flushed in the log.
All the entries from startTokenSafeToPersist to endToken must be maintained in hardDeleteRecoveryRange.
hardDeleteRecoveryRange may still have information of keys that have been persisted in certain cases, but this
does not affect the safety.
Note that we don't need any synchronization for this method as the hardDeleteRecoveryRange and all other
variables except startTokenSafeToPersist are only modified by the hardDeleteThread. Since startTokenSafeToPersist
gets modified by the IndexPersistorThread while this operation is in progress, we save it off first and use the
saved off value subsequently.
ambry-store/src/main/java/com/github/ambry/store/HardDeleter.java