public long submitServerCrash(ServerName serverName, boolean shouldSplitWal, boolean force) {
    // May be an 'Unknown Server' so handle case where serverNode is null.
    ServerStateNode serverNode = regionStates.getServerNode(serverName);
    // Remove the in-memory rsReports result
    synchronized (rsReports) {
      rsReports.remove(serverName);
    }
    if (serverNode == null) {
      if (force) {
        LOG.info("Force adding ServerCrashProcedure for {} when server node is null", serverName);
      } else {
        // for normal case, do not schedule SCP if ServerStateNode is null
        LOG.warn("Skip adding ServerCrashProcedure for {} because server node is null", serverName);
        return Procedure.NO_PROC_ID;
      }
    }

    ProcedureExecutor<MasterProcedureEnv> procExec = this.master.getMasterProcedureExecutor();
    // We hold the write lock here for fencing on reportRegionStateTransition. Once we set the
    // server state to CRASHED, we will no longer accept the reportRegionStateTransition call from
    // this server. This is used to simplify the implementation for TRSP and SCP, where we can make
    // sure that, the region list fetched by SCP will not be changed any more.
    if (serverNode != null) {
      serverNode.writeLock().lock();
    }
    try {

      boolean carryingMeta = isCarryingMeta(serverName);
      if (serverNode != null && !serverNode.isInState(ServerState.ONLINE)) {
        if (force) {
          LOG.info("Force adding ServerCrashProcedure for {} (meta={}) when state is not {}",
            serverNode, carryingMeta, ServerState.ONLINE);
        } else {
          LOG.info("Skip adding ServerCrashProcedure for {} (meta={}) when state is not {}",
            serverNode, carryingMeta, ServerState.ONLINE);
          return Procedure.NO_PROC_ID;
        }
      }
      MasterProcedureEnv mpe = procExec.getEnvironment();
      // If serverNode == null, then 'Unknown Server'. Schedule HBCKSCP instead.
      // HBCKSCP scours Master in-memory state AND hbase;meta for references to
      // serverName just-in-case. An SCP that is scheduled when the server is
      // 'Unknown' probably originated externally with HBCK2 fix-it tool.
      ServerState oldState = null;
      if (serverNode != null) {
        oldState = serverNode.getState();
        serverNode.setState(ServerState.CRASHED);
      }
      ServerCrashProcedure scp = force
        ? new HBCKServerCrashProcedure(mpe, serverName, shouldSplitWal, carryingMeta)
        : new ServerCrashProcedure(mpe, serverName, shouldSplitWal, carryingMeta);
      long pid = procExec.submitProcedure(scp);
      LOG.info("Scheduled ServerCrashProcedure pid={} for {} (carryingMeta={}){}.", pid, serverName,
        carryingMeta,
        serverNode == null ? "" : " " + serverNode.toString() + ", oldState=" + oldState);
      return pid;
    } finally {
      if (serverNode != null) {
        serverNode.writeLock().unlock();
      }
    }
  }
Usually run by the Master in reaction to server crash during normal processing. Can also be
invoked via external RPC to effect repair; in the latter case, the 'force' flag is set so we
push through the SCP though context may indicate already-running-SCP (An old SCP may have
exited abnormally, or damaged cluster may still have references in hbase:meta to 'Unknown
Servers' -- servers that are not online or in dead servers list, etc.)
@param force Set if the request came in externally over RPC (via hbck2). Force means run the
             SCP even if it seems as though there might be an outstanding SCP running.
@return pid of scheduled SCP or {@link Procedure#NO_PROC_ID} if none scheduled.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java