private boolean prepareMergeRegion(final MasterProcedureEnv env) throws IOException {
    // Fail if we are taking snapshot for the given table
    TableName tn = regionsToMerge[0].getTable();
    final String regionNamesToLog = RegionInfo.getShortNameToLog(regionsToMerge);
    if (env.getMasterServices().getSnapshotManager().isTableTakingAnySnapshot(tn)) {
      throw new MergeRegionException(
        "Skip merging regions " + regionNamesToLog + ", because we are snapshotting " + tn);
    }

    /*
     * Sometimes a ModifyTableProcedure has edited a table descriptor to change the number of region
     * replicas for a table, but it has not yet opened/closed the new replicas. The
     * ModifyTableProcedure assumes that nobody else will do the opening/closing of the new
     * replicas, but a concurrent MergeTableRegionProcedure would violate that assumption.
     */
    if (isTableModificationInProgress(env)) {
      setFailure(getClass().getSimpleName(),
        new IOException("Skip merging regions " + regionNamesToLog
          + ", because there is an active procedure that is modifying the table " + tn));
      return false;
    }

    // Mostly the below two checks are not used because we already check the switches before
    // submitting the merge procedure. Just for safety, we are checking the switch again here.
    // Also, in case the switch was set to false after submission, this procedure can be rollbacked,
    // thanks to this double check!
    // case 1: check for cluster level switch
    if (!env.getMasterServices().isSplitOrMergeEnabled(MasterSwitchType.MERGE)) {
      LOG.warn("Merge switch is off! skip merge of " + regionNamesToLog);
      setFailure(getClass().getSimpleName(),
        new IOException("Merge of " + regionNamesToLog + " failed because merge switch is off"));
      return false;
    }
    // case 2: check for table level switch
    if (!env.getMasterServices().getTableDescriptors().get(getTableName()).isMergeEnabled()) {
      LOG.warn("Merge is disabled for the table! Skipping merge of {}", regionNamesToLog);
      setFailure(getClass().getSimpleName(), new IOException(
        "Merge of " + regionNamesToLog + " failed as region merge is disabled for the table"));
      return false;
    }

    RegionStates regionStates = env.getAssignmentManager().getRegionStates();
    RegionStateStore regionStateStore = env.getAssignmentManager().getRegionStateStore();
    for (RegionInfo ri : this.regionsToMerge) {
      if (regionStateStore.hasMergeRegions(ri)) {
        String msg = "Skip merging " + regionNamesToLog + ", because a parent, "
          + RegionInfo.getShortNameToLog(ri) + ", has a merge qualifier "
          + "(if a 'merge column' in parent, it was recently merged but still has outstanding "
          + "references to its parents that must be cleared before it can participate in merge -- "
          + "major compact it to hurry clearing of its references)";
        LOG.warn(msg);
        throw new MergeRegionException(msg);
      }
      RegionState state = regionStates.getRegionState(ri.getEncodedName());
      if (state == null) {
        throw new UnknownRegionException(
          RegionInfo.getShortNameToLog(ri) + " UNKNOWN (Has it been garbage collected?)");
      }
      if (!state.isOpened()) {
        throw new MergeRegionException("Unable to merge regions that are NOT online: " + ri);
      }
      // Ask the remote regionserver if regions are mergeable. If we get an IOE, report it
      // along with the failure, so we can see why regions are not mergeable at this time.
      try {
        if (!isMergeable(env, state)) {
          setFailure(getClass().getSimpleName(),
            new MergeRegionException("Skip merging " + regionNamesToLog + ", because a parent, "
              + RegionInfo.getShortNameToLog(ri) + ", is not mergeable"));
          return false;
        }
      } catch (IOException e) {
        IOException ioe = new IOException(RegionInfo.getShortNameToLog(ri) + " NOT mergeable", e);
        setFailure(getClass().getSimpleName(), ioe);
        return false;
      }
    }

    // Update region states to Merging
    setRegionStateToMerging(env);
    return true;
  }
Prepare merge and do some check
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/MergeTableRegionsProcedure.java