private void verifyDataPostCompaction(Set<MockId> idsInCompactedLogSegments, Set<MockId> compactedDeletes,
      long deleteReferenceTimeMs) throws IOException, StoreException {
    for (MockId id : state.allKeys.keySet()) {
      if (state.liveKeys.contains(id)) {
        BlobReadOptions options = state.index.getBlobReadInfo(id, EnumSet.noneOf(StoreGetOptions.class));
        checkRecord(id, options);
        options.close();
        checkIndexValue(id);
      } else if (state.expiredKeys.contains(id)) {
        boolean shouldBeCompacted =
            idsInCompactedLogSegments.contains(id) && state.isExpiredAt(id, state.time.milliseconds());
        try {
          state.index.getBlobReadInfo(id, EnumSet.noneOf(StoreGetOptions.class));
          fail("Should not be able to GET " + id);
        } catch (StoreException e) {
          StoreErrorCodes expectedErrorCode = compactedDeletes.contains(id) ? StoreErrorCodes.IDNotFound
              : state.deletedKeys.contains(id) ? StoreErrorCodes.IDDeleted
                  : shouldBeCompacted ? StoreErrorCodes.IDNotFound : StoreErrorCodes.TTLExpired;
          assertEquals(id + " failed with error code " + e.getErrorCode(), expectedErrorCode, e.getErrorCode());
        }
        try {
          BlobReadOptions options = state.index.getBlobReadInfo(id, EnumSet.allOf(StoreGetOptions.class));
          if (shouldBeCompacted) {
            fail("Should not be able to GET " + id);
          } else {
            checkRecord(id, options);
            options.close();
            checkIndexValue(id);
          }
        } catch (StoreException e) {
          assertTrue("Blob for " + id + " should have been retrieved", shouldBeCompacted);
          StoreErrorCodes expectedErrorCode = compactedDeletes.contains(id) ? StoreErrorCodes.IDNotFound
              : state.deletedKeys.contains(id) ? StoreErrorCodes.IDDeleted : StoreErrorCodes.IDNotFound;
          assertEquals(id + " failed with error code " + e.getErrorCode(), expectedErrorCode, e.getErrorCode());
        }
      } else if (state.deletedKeys.contains(id)) {
        IndexValue latestValue = state.getExpectedValue(id, false);
        boolean shouldBeAbsent = state.getExpectedValue(id, true) == null || (idsInCompactedLogSegments.contains(id)
            && latestValue.getOperationTimeInMs() < deleteReferenceTimeMs);
        try {
          state.index.getBlobReadInfo(id, EnumSet.noneOf(StoreGetOptions.class));
          fail("Should not be able to GET " + id);
        } catch (StoreException e) {
          StoreErrorCodes expectedErrorCode =
              compactedDeletes.contains(id) ? StoreErrorCodes.IDNotFound : StoreErrorCodes.IDDeleted;
          if (expectedErrorCode != e.getErrorCode()) {
            assertEquals(id + " failed with error code " + e.getErrorCode(), expectedErrorCode, e.getErrorCode());
          }
        }
        try {
          BlobReadOptions options = state.index.getBlobReadInfo(id, EnumSet.allOf(StoreGetOptions.class));
          if (shouldBeAbsent) {
            fail("Should not be able to GET " + id);
          } else {
            checkRecord(id, options);
            options.close();
            checkIndexValue(id);
          }
        } catch (StoreException e) {
          assertTrue("Blob for " + id + " should have been retrieved", shouldBeAbsent);
          StoreErrorCodes expectedErrorCode =
              compactedDeletes.contains(id) ? StoreErrorCodes.IDNotFound : StoreErrorCodes.IDDeleted;
          assertEquals(id + " failed with error code " + e.getErrorCode(), expectedErrorCode, e.getErrorCode());
        }
      }
    }
  }
Verifies data after compaction is finished.
1. Checks that GET of data of live keys succeeds without any flags.
2. Checks that GET of data of deleted keys returns deleted. Also verifies that when GET is used with
{@link StoreGetOptions#Store_Include_Deleted}, data is returned if it was not compacted and not returned if
compacted.
3. Checks that GET of data of expired keys returns expired if not compacted and not found if compacted. Also
verifies that when GET is used with {@link StoreGetOptions#Store_Include_Expired}, data is returned if it was not
compacted and not returned if compacted.
@param idsInCompactedLogSegments the ids that had PUT records in the segments that were compacted.
@param compactedDeletes a set of delete tombstone ids that should be cleaned up in compacted segments.
@param deleteReferenceTimeMs the reference time in ms to use to decide whether deletes are valid.
@throws IOException
@throws StoreException
ambry-store/src/test/java/com/github/ambry/store/BlobStoreCompactorTest.java