private boolean isTtlUpdateEntryValid(StoreKey key, IndexValue ttlUpdateValue, long referenceTimeInMs,
      FileSpan fileSpanUnderCompaction, Map<StoreKey, IndexFinalState> keyFinalStates) throws StoreException {
    // Offset sanity check
    if (ttlUpdateValue.getOffset().compareTo(index.getStartOffset()) < 0) {
      return false;
    }
    // Validity of ttl update is determined by the logic like this
    // Is there PUT before this ttl update
    //   NO: invalid
    //   YES: is the final state a delete and out of retention
    //     NO: valid
    //     YES: is ttl update NOT in the same log as put || is put NOT under compaction
    //       YES: valid
    //       NO: invalid
    FileSpan searchSpan = new FileSpan(index.getStartOffset(), ttlUpdateValue.getOffset());
    IndexValue putValue = index.findKey(key, searchSpan, EnumSet.of(PersistentIndex.IndexEntryType.PUT));
    IndexFinalState finalState = keyFinalStates.get(key);
    boolean valid = true;
    if (putValue == null) {
      valid = false;
    } else if (finalState != null && finalState.isDelete() && finalState.getOperationTime() < referenceTimeInMs) {
      if (fileSpanUnderCompaction != null) {
        valid = !fileSpanUnderCompaction.inSpan(putValue.getOffset());
      } else {
        valid = !putValue.getOffset().getName().equals(ttlUpdateValue.getOffset().getName());
      }
    }

    if (valid && !keyFinalStates.containsKey(key)) {
      keyFinalStates.put(key, new IndexFinalState(ttlUpdateValue.getFlags(), ttlUpdateValue.getOperationTimeInMs(),
          ttlUpdateValue.getLifeVersion(), ttlUpdateValue.getSize(), ttlUpdateValue.getExpiresAtMs(),
          ttlUpdateValue.getOffset()));
    }
    // else, valid = true because a ttl update entry with a put in another log segment is considered valid as long as
    // the put still exists (regardless of its validity)
    return valid;
  }
@param key the {@link StoreKey} to check
@param ttlUpdateValue the {@link IndexValue} of the TTL update entry of {@code key}
@param referenceTimeInMs the reference time in ms until which deletes are relevant
@param keyFinalStates a {@link Map} of key to {@link IndexFinalState}.
@return {@code true} if the ttl update entry is valid
@throws StoreException if there are problems accessing the index
ambry-store/src/main/java/com/github/ambry/store/BlobStoreStats.java