protected ArrayList<HStoreFile> applyCompactionPolicy(ArrayList<HStoreFile> candidates,
    boolean mayUseOffPeak, boolean mayBeStuck) throws IOException {
    if (candidates.isEmpty()) {
      return candidates;
    }

    // we're doing a minor compaction, let's see what files are applicable
    int start = 0;
    double ratio = comConf.getCompactionRatio();
    if (mayUseOffPeak) {
      ratio = comConf.getCompactionRatioOffPeak();
      LOG.info("Running an off-peak compaction, selection ratio = " + ratio);
    }

    // get store file sizes for incremental compacting selection.
    final int countOfFiles = candidates.size();
    long[] fileSizes = new long[countOfFiles];
    long[] sumSize = new long[countOfFiles];
    for (int i = countOfFiles - 1; i >= 0; --i) {
      HStoreFile file = candidates.get(i);
      fileSizes[i] = file.getReader().length();
      // calculate the sum of fileSizes[i,i+maxFilesToCompact-1) for algo
      int tooFar = i + comConf.getMaxFilesToCompact() - 1;
      sumSize[i] = fileSizes[i] + ((i + 1 < countOfFiles) ? sumSize[i + 1] : 0)
        - ((tooFar < countOfFiles) ? fileSizes[tooFar] : 0);
    }

    while (
      countOfFiles - start >= comConf.getMinFilesToCompact() && fileSizes[start]
          > Math.max(comConf.getMinCompactSize(), (long) (sumSize[start + 1] * ratio))
    ) {
      ++start;
    }
    if (start < countOfFiles) {
      LOG.info("Default compaction algorithm has selected " + (countOfFiles - start)
        + " files from " + countOfFiles + " candidates");
    } else if (mayBeStuck) {
      // We may be stuck. Compact the latest files if we can.
      int filesToLeave = candidates.size() - comConf.getMinFilesToCompact();
      if (filesToLeave >= 0) {
        start = filesToLeave;
      }
    }
    candidates.subList(0, start).clear();
    return candidates;
  }
-- Default minor compaction selection algorithm: choose CompactSelection from candidates --
First exclude bulk-load files if indicated in configuration. Start at the oldest file and stop
when you find the first file that meets compaction criteria: (1) a recently-flushed, small file
(i.e. <= minCompactSize) OR (2) within the compactRatio of sum(newer_files) Given normal skew,
any newer files will also meet this criteria
<p/>
Additional Note: If fileSizes.size() >> maxFilesToCompact, we will recurse on compact().
Consider the oldest files first to avoid a situation where we always compact
[end-threshold,end). Then, the last file becomes an aggregate of the previous compactions.
normal skew: older ----> newer (increasing seqID) _ | | _ | | | | _ --|-|- |-|-
|-|---_-------_------- minCompactSize | | | | | | | | _ | | | | | | | | | | | | | | | | | | | |
| | | | | |
@param candidates pre-filtrate
@return filtered subset
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/RatioBasedCompactionPolicy.java