private void doInterruptionDuringRecordCopyTest() throws Exception {
    bundleReadBuffer = null;
    for (long interruptAt : Arrays.asList(PUT_RECORD_SIZE, -2 * PUT_RECORD_SIZE)) {
      // no change before expiry time
      Pair<Long, List<LogSegmentName>> expiryTimeAndSegmentsUnderCompaction =
          setupStateWithExpiredBlobsAtSpecificTime();
      List<LogSegmentName> segmentsUnderCompaction = expiryTimeAndSegmentsUnderCompaction.getSecond();
      Map<LogSegmentName, Long> oldSegmentNamesAndEndOffsets = getEndOffsets(segmentsUnderCompaction);
      // if negative, set crash count starting from the end
      long countToInterruptAt = interruptAt;
      if (countToInterruptAt < 0) {
        // while copying each index segment, the bytes copied for the last record is not reported to the diskIOScheduler
        long unreported = getIndexSegmentStartOffsetsForLogSegments(segmentsUnderCompaction).size() * PUT_RECORD_SIZE;
        countToInterruptAt +=
            getValidDataSize(segmentsUnderCompaction, state.time.milliseconds(), purgeDeleteTombstone) - unreported;
      }
      // create a DiskIOScheduler
      DiskIOScheduler diskIOScheduler = new InterruptionInducingDiskIOScheduler(Integer.MAX_VALUE, countToInterruptAt);
      compactWithRecoveryAndVerify(state.log, diskIOScheduler, state.index, segmentsUnderCompaction,
          state.time.milliseconds(), false, true);
      verifyNoChangeInEndOffsets(oldSegmentNamesAndEndOffsets);

      // there will be changes past expiration time
      expiryTimeAndSegmentsUnderCompaction = setupStateWithExpiredBlobsAtSpecificTime();
      segmentsUnderCompaction = expiryTimeAndSegmentsUnderCompaction.getSecond();
      state.advanceTime(expiryTimeAndSegmentsUnderCompaction.getFirst() + Time.MsPerSec - state.time.milliseconds());
      countToInterruptAt = interruptAt;
      if (countToInterruptAt < 0) {
        // while copying each index segment, the bytes copied for the last record is not reported to the diskIOScheduler
        long unreported = getIndexSegmentStartOffsetsForLogSegments(segmentsUnderCompaction).size() * PUT_RECORD_SIZE;
        countToInterruptAt +=
            getValidDataSize(segmentsUnderCompaction, state.time.milliseconds(), purgeDeleteTombstone) - unreported;
      }
      diskIOScheduler = new InterruptionInducingDiskIOScheduler(Integer.MAX_VALUE, countToInterruptAt);
      compactWithRecoveryAndVerify(state.log, diskIOScheduler, state.index, segmentsUnderCompaction,
          state.time.milliseconds(), true, true);
    }
  }
Does compaction tests where compaction is interrupted (and recovered) after copying a few records from an index
segment.
@throws Exception
ambry-store/src/test/java/com/github/ambry/store/BlobStoreCompactorTest.java