public boolean prepareSplitRegion(final MasterProcedureEnv env) throws IOException {
    // Fail if we are taking snapshot for the given table
    if (
      env.getMasterServices().getSnapshotManager()
        .isTableTakingAnySnapshot(getParentRegion().getTable())
    ) {
      setFailure(new IOException("Skip splitting region " + getParentRegion().getShortNameToLog()
        + ", because we are taking snapshot for the table " + getParentRegion().getTable()));
      return false;
    }

    /*
     * 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 SplitTableRegionProcedure would violate that assumption.
     */
    if (checkTableModifyInProgress && isTableModificationInProgress(env)) {
      setFailure(new IOException("Skip splitting region " + getParentRegion().getShortNameToLog()
        + ", because there is an active procedure that is modifying the table "
        + getParentRegion().getTable()));
      return false;
    }

    // Check whether the region is splittable
    RegionStateNode node =
      env.getAssignmentManager().getRegionStates().getRegionStateNode(getParentRegion());

    if (node == null) {
      throw new UnknownRegionException(getParentRegion().getRegionNameAsString());
    }

    RegionInfo parentHRI = node.getRegionInfo();
    if (parentHRI == null) {
      LOG.info("Unsplittable; parent region is null; node={}", node);
      return false;
    }
    // Lookup the parent HRI state from the AM, which has the latest updated info.
    // Protect against the case where concurrent SPLIT requests came in and succeeded
    // just before us.
    if (node.isInState(State.SPLIT)) {
      LOG.info("Split of " + parentHRI + " skipped; state is already SPLIT");
      return false;
    }
    if (parentHRI.isSplit() || parentHRI.isOffline()) {
      LOG.info("Split of " + parentHRI + " skipped because offline/split.");
      return false;
    }

    // expected parent to be online or closed
    if (!node.isInState(EXPECTED_SPLIT_STATES)) {
      // We may have SPLIT already?
      setFailure(
        new IOException("Split " + parentHRI.getRegionNameAsString() + " FAILED because state="
          + node.getState() + "; expected " + Arrays.toString(EXPECTED_SPLIT_STATES)));
      return false;
    }

    // Mostly the below two checks are not used because we already check the switches before
    // submitting the split 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.SPLIT)) {
      LOG.warn("pid=" + getProcId() + " split switch is off! skip split of " + parentHRI);
      setFailure(new IOException(
        "Split region " + parentHRI.getRegionNameAsString() + " failed due to split switch off"));
      return false;
    }
    // case 2: check for table level switch
    if (!env.getMasterServices().getTableDescriptors().get(getTableName()).isSplitEnabled()) {
      LOG.warn("pid={}, split is disabled for the table! Skipping split of {}", getProcId(),
        parentHRI);
      setFailure(new IOException("Split region " + parentHRI.getRegionNameAsString()
        + " failed as region split is disabled for the table"));
      return false;
    }

    // set node state as SPLITTING
    node.setState(State.SPLITTING);

    // Since we have the lock and the master is coordinating the operation
    // we are always able to split the region
    return true;
  }
Prepare to Split region.
@param env MasterProcedureEnv
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/SplitTableRegionProcedure.java