private boolean copyDataByIndexSegment(LogSegment logSegmentToCopy, IndexSegment indexSegmentToCopy,
      FileSpan duplicateSearchSpan) throws IOException, StoreException {
    logger.debug("Copying data from {}", indexSegmentToCopy.getFile());

    // Here we add the pair of before and after index segment offsets to the compaction log. This pair would be useful
    // in replication thread. In replication thread, when a remote peer sends a replication token to resume replication,
    // the token would have an offset to indicate which index segment this token is pointing to if it's index based token.
    // However, this index segment would be removed if the log segment is under compaction. Here we save the pair of start
    // offsets of index segments before and after compaction so in replication thread, we can just reset the token back to
    // the after compaction index segment start offset when the before compaction index segment is removed.
    // We are adding the offsets without knowing if any of the content from the current index segment would be copied to the
    // target. Even if there is no content from this index segment that would be preserved after compaction, we still want to
    // save this pair of index segment offsets since replication might be working on this index segment. And it also
    // indicates that last index segment finishes copying.
    compactionLog.addBeforeAndAfterIndexSegmentOffsetPair(indexSegmentToCopy.getStartOffset(),
        tgtIndex.getActiveIndexSegmentOffset());

    // call into diskIOScheduler to make sure we can proceed (assuming it won't be 0).
    diskIOScheduler.getSlice(INDEX_SEGMENT_READ_JOB_NAME, INDEX_SEGMENT_READ_JOB_NAME, 1);
    boolean checkAlreadyCopied = isIndexSegmentUnderCopy(indexSegmentToCopy.getStartOffset());
    logger.trace("Should check already copied for {}: {} ", indexSegmentToCopy.getFile(), checkAlreadyCopied);

    List<IndexEntry> indexEntriesToCopy =
        validEntryFilter.getValidEntry(indexSegmentToCopy, duplicateSearchSpan, checkAlreadyCopied);
    long dataSize = indexEntriesToCopy.stream().mapToLong(entry -> entry.getValue().getSize()).sum();
    logger.trace("{} entries/{} bytes need to be copied in {} with {}", indexEntriesToCopy.size(), dataSize,
        indexSegmentToCopy.getFile(), storeId);

    if (indexEntriesToCopy.isEmpty()) {
      return true;
    }
    // Copy these over
    long startTime = SystemTime.getInstance().milliseconds();
    boolean copiedAll = copyRecords(logSegmentToCopy, indexEntriesToCopy, indexSegmentToCopy.getLastModifiedTimeSecs());
    srcMetrics.compactionCopyRecordTimeInMs.update(SystemTime.getInstance().milliseconds() - startTime,
        TimeUnit.MILLISECONDS);
    // persist
    tgtIndex.persistIndex();
    return copiedAll;
  }
Copies data in the provided {@code indexSegmentToCopy} into the target log (swap spaces).
@param logSegmentToCopy the {@link LogSegment} to copy from.
@param indexSegmentToCopy the {@link IndexSegment} that contains the entries that need to be copied.
@param duplicateSearchSpan the {@link FileSpan} in which to search for duplicates.
@return {@code true} if all the records in the index segment were copied. {@code false} if some records were not
copied either because there was no more capacity or because a shutdown was initiated.
@throws IOException if there were I/O errors during copying.
@throws StoreException if there are any problems reading or writing to store components.
ambry-store/src/main/java/com/github/ambry/store/BlobStoreCompactor.java