void mergeOverlaps(Collection<HbckRegionInfo> overlap) throws IOException {
      String thread = Thread.currentThread().getName();
      LOG.info(
        "== [" + thread + "] Merging regions into one region: " + Joiner.on(",").join(overlap));
      // get the min / max range and close all concerned regions
      Pair<byte[], byte[]> range = null;
      for (HbckRegionInfo hi : overlap) {
        if (range == null) {
          range = new Pair<>(hi.getStartKey(), hi.getEndKey());
        } else {
          if (
            RegionSplitCalculator.BYTES_COMPARATOR.compare(hi.getStartKey(), range.getFirst()) < 0
          ) {
            range.setFirst(hi.getStartKey());
          }
          if (
            RegionSplitCalculator.BYTES_COMPARATOR.compare(hi.getEndKey(), range.getSecond()) > 0
          ) {
            range.setSecond(hi.getEndKey());
          }
        }
        // need to close files so delete can happen.
        LOG.debug("[" + thread + "] Closing region before moving data around: " + hi);
        LOG.debug("[" + thread + "] Contained region dir before close");
        hbck.debugLsr(hi.getHdfsRegionDir());
        try {
          LOG.info("[" + thread + "] Closing region: " + hi);
          hbck.closeRegion(hi);
        } catch (IOException ioe) {
          LOG.warn("[" + thread + "] Was unable to close region " + hi + ".  Just continuing... ",
            ioe);
        } catch (InterruptedException e) {
          LOG.warn("[" + thread + "] Was unable to close region " + hi + ".  Just continuing... ",
            e);
        }

        try {
          LOG.info("[" + thread + "] Offlining region: " + hi);
          hbck.offline(hi.getRegionName());
        } catch (IOException ioe) {
          LOG.warn("[" + thread + "] Unable to offline region from master: " + hi
            + ".  Just continuing... ", ioe);
        }
      }

      // create new empty container region.
      TableDescriptor htd = getTableInfo().getTableDescriptor();
      // from start key to end Key
      RegionInfo newRegion = RegionInfoBuilder.newBuilder(htd.getTableName())
        .setStartKey(range.getFirst()).setEndKey(range.getSecond()).build();
      HRegion region = HBaseFsckRepair.createHDFSRegionDir(conf, newRegion, htd);
      LOG.info("[" + thread + "] Created new empty container region: " + newRegion
        + " to contain regions: " + Joiner.on(",").join(overlap));
      hbck.debugLsr(region.getRegionFileSystem().getRegionDir());

      // all target regions are closed, should be able to safely cleanup.
      boolean didFix = false;
      Path target = region.getRegionFileSystem().getRegionDir();
      for (HbckRegionInfo contained : overlap) {
        LOG.info("[" + thread + "] Merging " + contained + " into " + target);
        int merges = hbck.mergeRegionDirs(target, contained);
        if (merges > 0) {
          didFix = true;
        }
      }
      if (didFix) {
        hbck.fixes++;
      }
    }
This takes set of overlapping regions and merges them into a single region. This covers cases
like degenerate regions, shared start key, general overlaps, duplicate ranges, and partial
overlapping regions. Cases: - Clean regions that overlap - Only .oldlogs regions (can't find
start/stop range, or figure out) This is basically threadsafe, except for the fixer increment
in mergeOverlaps.
hbase-server/src/main/java/org/apache/hadoop/hbase/util/HbckTableInfo.java