private void processEntryForLogSegmentBucket(ScanResults results, IndexEntry indexEntry,
      Map<StoreKey, IndexFinalState> keyFinalStates) {
    IndexValue indexValue = indexEntry.getValue();
    results.updateLogSegmentBaseBucket(indexValue.getOffset().getName(), indexValue.getSize());
    if (indexValue.isPut()) {
      long expiresAtMs = indexValue.getExpiresAtMs();
      long deleteAtMs = Utils.Infinite_Time;
      IndexFinalState finalState = keyFinalStates.get(indexEntry.getKey());
      if (finalState != null && finalState.isDelete()) {
        deleteAtMs = finalState.getOperationTime();
      }
      if (expiresAtMs == Utils.Infinite_Time && deleteAtMs != Utils.Infinite_Time) {
        handleLogSegmentDeletedBucketUpdate(results, indexValue, deleteAtMs, SUBTRACT);
      } else if (expiresAtMs != Utils.Infinite_Time && deleteAtMs == Utils.Infinite_Time) {
        handleLogSegmentExpiredBucketUpdate(results, indexValue, expiresAtMs, SUBTRACT);
      } else if (expiresAtMs != Utils.Infinite_Time && deleteAtMs != Utils.Infinite_Time) {
        // TODO: should compare expiresAtMs with deleteAtMs or deleteAtMs + deleteRetentionTime?
        if (expiresAtMs < deleteAtMs) {
          handleLogSegmentExpiredBucketUpdate(results, indexValue, expiresAtMs, SUBTRACT);
        } else {
          handleLogSegmentDeletedBucketUpdate(results, indexValue, deleteAtMs, SUBTRACT);
        }
      }
    } else if (!indexValue.isDelete() && !indexValue.isUndelete() && indexValue.isTtlUpdate()) {
      IndexFinalState finalState = keyFinalStates.get(indexEntry.getKey());
      if (finalState != null && finalState.isDelete()) {
        Offset beginningOfThisLogSegment = new Offset(indexValue.getOffset().getName(), LogSegment.HEADER_SIZE);
        FileSpan fileSpan = new FileSpan(beginningOfThisLogSegment, indexValue.getOffset());
        try {
          IndexValue putValue =
              index.findKey(indexEntry.getKey(), fileSpan, EnumSet.of(PersistentIndex.IndexEntryType.PUT));
          if (putValue != null) {
            // When the Put IndexValue is in the same log segment as the TTL_UPDATE value, then TTL_UPDATE value is invalid.
            handleLogSegmentDeletedBucketUpdate(results, indexValue, finalState.getOperationTime(), SUBTRACT);
          }
        } catch (StoreException e) {
          logger.error("Failed to find PUT IndexEntry for key {} in filespan {}", indexEntry.getKey(), fileSpan, e);
        }
      }
    }
  }
Process a {@link List} of valid {@link IndexEntry} based on forecast boundaries and populate corresponding
log segment buckets in the given {@link ScanResults}.
@param results the {@link ScanResults} to be populated
@param indexEntry a {@link List} of valid {@link IndexEntry} to be processed
@param keyFinalStates a {@link Map} of key to {@link IndexFinalState}.
ambry-store/src/main/java/com/github/ambry/store/BlobStoreStats.java