protected List<HStoreFile> doCompaction(CompactionRequestImpl cr,
    Collection<HStoreFile> filesToCompact, User user, long compactionStartTime, List<Path> newFiles)
    throws IOException {
    // Do the steps necessary to complete the compaction.
    setStoragePolicyFromFileName(newFiles);
    List<HStoreFile> sfs = storeEngine.commitStoreFiles(newFiles, true, true);
    if (this.getCoprocessorHost() != null) {
      for (HStoreFile sf : sfs) {
        getCoprocessorHost().postCompact(this, sf, cr.getTracker(), cr, user);
      }
    }
    replaceStoreFiles(filesToCompact, sfs, true);

    long outputBytes = getTotalSize(sfs);

    // At this point the store will use new files for all new scanners.
    refreshStoreSizeAndTotalBytes(); // update store size.

    long now = EnvironmentEdgeManager.currentTime();
    if (
      region.getRegionServerServices() != null
        && region.getRegionServerServices().getMetrics() != null
    ) {
      region.getRegionServerServices().getMetrics().updateCompaction(
        region.getTableDescriptor().getTableName().getNameAsString(), cr.isMajor(),
        now - compactionStartTime, cr.getFiles().size(), newFiles.size(), cr.getSize(),
        outputBytes);

    }

    logCompactionEndMessage(cr, sfs, now, compactionStartTime);
    return sfs;
  }
Compact the StoreFiles. This method may take some time, so the calling thread must be able to
block for long periods.
<p>
During this time, the Store can work as usual, getting values from StoreFiles and writing new
StoreFiles from the MemStore. Existing StoreFiles are not destroyed until the new compacted
StoreFile is completely written-out to disk.
<p>
The compactLock prevents multiple simultaneous compactions. The structureLock prevents us from
interfering with other write operations.
<p>
We don't want to hold the structureLock for the whole time, as a compact() can be lengthy and
we want to allow cache-flushes during this period.
<p>
Compaction event should be idempotent, since there is no IO Fencing for the region directory in
hdfs. A region server might still try to complete the compaction after it lost the region. That
is why the following events are carefully ordered for a compaction:
<ol>
<li>Compaction writes new files under region/.tmp directory (compaction output)</li>
<li>Compaction atomically moves the temporary file under region directory</li>
<li>Compaction appends a WAL edit containing the compaction input and output files. Forces sync
on WAL.</li>
<li>Compaction deletes the input files from the region directory.</li>
</ol>
Failure conditions are handled like this:
<ul>
<li>If RS fails before 2, compaction won't complete. Even if RS lives on and finishes the
compaction later, it will only write the new data file to the region directory. Since we
already have this data, this will be idempotent, but we will have a redundant copy of the
data.</li>
<li>If RS fails between 2 and 3, the region will have a redundant copy of the data. The RS that
failed won't be able to finish sync() for WAL because of lease recovery in WAL.</li>
<li>If RS fails after 3, the region server who opens the region will pick up the compaction
marker from the WAL and replay it by removing the compaction input files. Failed RS can also
attempt to delete those files, but the operation will be idempotent</li>
</ul>
See HBASE-2231 for details.
@param compaction compaction details obtained from requestCompaction()
@return The storefiles that we compacted into or null if we failed or opted out early.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java