public boolean checkRegionChain(TableIntegrityErrorHandler handler) throws IOException {
    // When table is disabled no need to check for the region chain. Some of the regions
    // accidently if deployed, this below code might report some issues like missing start
    // or end regions or region hole in chain and may try to fix which is unwanted.
    if (hbck.isTableDisabled(this.tableName)) {
      return true;
    }
    int originalErrorsCount = hbck.getErrors().getErrorList().size();
    Multimap<byte[], HbckRegionInfo> regions = sc.calcCoverage();
    SortedSet<byte[]> splits = sc.getSplits();

    byte[] prevKey = null;
    byte[] problemKey = null;

    if (splits.isEmpty()) {
      // no region for this table
      handler.handleHoleInRegionChain(HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
    }

    for (byte[] key : splits) {
      Collection<HbckRegionInfo> ranges = regions.get(key);
      if (prevKey == null && !Bytes.equals(key, HConstants.EMPTY_BYTE_ARRAY)) {
        for (HbckRegionInfo rng : ranges) {
          handler.handleRegionStartKeyNotEmpty(rng);
        }
      }

      // check for degenerate ranges
      for (HbckRegionInfo rng : ranges) {
        // special endkey case converts '' to null
        byte[] endKey = rng.getEndKey();
        endKey = (endKey.length == 0) ? null : endKey;
        if (Bytes.equals(rng.getStartKey(), endKey)) {
          handler.handleDegenerateRegion(rng);
        }
      }

      if (ranges.size() == 1) {
        // this split key is ok -- no overlap, not a hole.
        if (problemKey != null) {
          LOG.warn("reached end of problem group: " + Bytes.toStringBinary(key));
        }
        problemKey = null; // fell through, no more problem.
      } else if (ranges.size() > 1) {
        // set the new problem key group name, if already have problem key, just
        // keep using it.
        if (problemKey == null) {
          // only for overlap regions.
          LOG.warn("Naming new problem group: " + Bytes.toStringBinary(key));
          problemKey = key;
        }
        overlapGroups.putAll(problemKey, ranges);

        // record errors
        ArrayList<HbckRegionInfo> subRange = new ArrayList<>(ranges);
        // this dumb and n^2 but this shouldn't happen often
        for (HbckRegionInfo r1 : ranges) {
          if (r1.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) {
            continue;
          }
          subRange.remove(r1);
          for (HbckRegionInfo r2 : subRange) {
            if (r2.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) {
              continue;
            }
            // general case of same start key
            if (Bytes.compareTo(r1.getStartKey(), r2.getStartKey()) == 0) {
              handler.handleDuplicateStartKeys(r1, r2);
            } else if (
              Bytes.compareTo(r1.getEndKey(), r2.getStartKey()) == 0
                && r1.getHdfsHRI().getRegionId() == r2.getHdfsHRI().getRegionId()
            ) {
              LOG.info("this is a split, log to splits");
              handler.handleSplit(r1, r2);
            } else {
              // overlap
              handler.handleOverlapInRegionChain(r1, r2);
            }
          }
        }

      } else if (ranges.isEmpty()) {
        if (problemKey != null) {
          LOG.warn("reached end of problem group: " + Bytes.toStringBinary(key));
        }
        problemKey = null;

        byte[] holeStopKey = sc.getSplits().higher(key);
        // if higher key is null we reached the top.
        if (holeStopKey != null) {
          // hole
          handler.handleHoleInRegionChain(key, holeStopKey);
        }
      }
      prevKey = key;
    }

    // When the last region of a table is proper and having an empty end key, 'prevKey'
    // will be null.
    if (prevKey != null) {
      handler.handleRegionEndKeyNotEmpty(prevKey);
    }

    // TODO fold this into the TableIntegrityHandler
    if (hbck.getConf().getBoolean("hbasefsck.overlap.merge.parallel", true)) {
      boolean ok = handleOverlapsParallel(handler, prevKey);
      if (!ok) {
        return false;
      }
    } else {
      for (Collection<HbckRegionInfo> overlap : overlapGroups.asMap().values()) {
        handler.handleOverlapGroup(overlap);
      }
    }

    if (HBaseFsck.shouldDisplayFullReport()) {
      // do full region split map dump
      hbck.getErrors().print("---- Table '" + this.tableName + "': region split map");
      dump(splits, regions);
      hbck.getErrors().print("---- Table '" + this.tableName + "': overlap groups");
      dumpOverlapProblems(overlapGroups);
      hbck.getErrors().print("There are " + overlapGroups.keySet().size() + " overlap groups with "
        + overlapGroups.size() + " overlapping regions");
    }
    if (!sidelinedRegions.isEmpty()) {
      LOG.warn("Sidelined big overlapped regions, please bulk load them!");
      hbck.getErrors()
        .print("---- Table '" + this.tableName + "': sidelined big overlapped regions");
      dumpSidelinedRegions(sidelinedRegions);
    }
    return hbck.getErrors().getErrorList().size() == originalErrorsCount;
  }
Check the region chain (from META) of this table. We are looking for holes, overlaps, and
cycles.
@return false if there are errors
hbase-server/src/main/java/org/apache/hadoop/hbase/util/HbckTableInfo.java