protected StripeCompactionRequest selectSingleStripeCompaction(StripeInformationProvider si,
    boolean includeL0, boolean canDropDeletesWithoutL0, boolean isOffpeak) throws IOException {
    ArrayList<ImmutableList<HStoreFile>> stripes = si.getStripes();

    int bqIndex = -1;
    List<HStoreFile> bqSelection = null;
    int stripeCount = stripes.size();
    long bqTotalSize = -1;
    for (int i = 0; i < stripeCount; ++i) {
      // If we want to compact L0 to drop deletes, we only want whole-stripe compactions.
      // So, pass includeL0 as 2nd parameter to indicate that.
      List<HStoreFile> selection = selectSimpleCompaction(stripes.get(i),
        !canDropDeletesWithoutL0 && includeL0, isOffpeak, false);
      if (selection.isEmpty()) continue;
      long size = 0;
      for (HStoreFile sf : selection) {
        size += sf.getReader().length();
      }
      if (
        bqSelection == null || selection.size() > bqSelection.size()
          || (selection.size() == bqSelection.size() && size < bqTotalSize)
      ) {
        bqSelection = selection;
        bqIndex = i;
        bqTotalSize = size;
      }
    }
    if (bqSelection == null) {
      LOG.debug("No good compaction is possible in any stripe");
      return null;
    }
    List<HStoreFile> filesToCompact = new ArrayList<>(bqSelection);
    // See if we can, and need to, split this stripe.
    int targetCount = 1;
    long targetKvs = Long.MAX_VALUE;
    boolean hasAllFiles = filesToCompact.size() == stripes.get(bqIndex).size();
    String splitString = "";
    if (hasAllFiles && bqTotalSize >= config.getSplitSize()) {
      if (includeL0) {
        // We want to avoid the scenario where we compact a stripe w/L0 and then split it.
        // So, if we might split, don't compact the stripe with L0.
        return null;
      }
      Pair<Long, Integer> kvsAndCount = estimateTargetKvs(filesToCompact, config.getSplitCount());
      targetKvs = kvsAndCount.getFirst();
      targetCount = kvsAndCount.getSecond();
      splitString = "; the stripe will be split into at most " + targetCount + " stripes with "
        + targetKvs + " target KVs";
    }

    LOG.debug("Found compaction in a stripe with end key [" + Bytes.toString(si.getEndRow(bqIndex))
      + "], with " + filesToCompact.size() + " files of total size " + bqTotalSize + splitString);

    // See if we can drop deletes.
    StripeCompactionRequest req;
    if (includeL0) {
      assert hasAllFiles;
      List<HStoreFile> l0Files = si.getLevel0Files();
      LOG.debug("Adding " + l0Files.size() + " files to compaction to be able to drop deletes");
      ConcatenatedLists<HStoreFile> sfs = new ConcatenatedLists<>();
      sfs.addSublist(filesToCompact);
      sfs.addSublist(l0Files);
      req = new BoundaryStripeCompactionRequest(sfs, si.getStripeBoundaries());
    } else {
      req = new SplitStripeCompactionRequest(filesToCompact, si.getStartRow(bqIndex),
        si.getEndRow(bqIndex), targetCount, targetKvs);
    }
    if (hasAllFiles && (canDropDeletesWithoutL0 || includeL0)) {
      req.setMajorRange(si.getStartRow(bqIndex), si.getEndRow(bqIndex));
    }
    req.getRequest().setOffPeak(isOffpeak);
    return req;
  }
@param si StoreFileManager.
@return Whether any stripe potentially needs compaction.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/compactions/StripeCompactionPolicy.java