@Override
  protected Procedure<MasterProcedureEnv>[] execute(MasterProcedureEnv env)
    throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException {
    if (dispatched) {
      if (succ) {
        return null;
      }
      dispatched = false;
    }

    RegionStates regionStates = env.getAssignmentManager().getRegionStates();
    RegionStateNode regionNode = regionStates.getRegionStateNode(region);
    regionNode.lock();
    try {
      if (regionNode.getProcedure() != null) {
        setTimeoutForSuspend(env, String.format("region %s has a TRSP attached %s",
          region.getRegionNameAsString(), regionNode.getProcedure()));
        throw new ProcedureSuspendedException();
      }
      if (!regionNode.isInState(RegionState.State.OPEN)) {
        setTimeoutForSuspend(env, String.format("region state of %s is %s",
          region.getRegionNameAsString(), regionNode.getState()));
        throw new ProcedureSuspendedException();
      }
      ServerName targetServer = regionNode.getRegionLocation();
      if (targetServer == null) {
        setTimeoutForSuspend(env,
          String.format("target server of region %s is null", region.getRegionNameAsString()));
        throw new ProcedureSuspendedException();
      }
      ServerState serverState = regionStates.getServerNode(targetServer).getState();
      if (serverState != ServerState.ONLINE) {
        setTimeoutForSuspend(env, String.format("target server of region %s %s is in state %s",
          region.getRegionNameAsString(), targetServer, serverState));
        throw new ProcedureSuspendedException();
      }
      try {
        env.getRemoteDispatcher().addOperationToNode(targetServer, this);
        dispatched = true;
        event = new ProcedureEvent<>(this);
        event.suspendIfNotReady(this);
        throw new ProcedureSuspendedException();
      } catch (FailedRemoteDispatchException e) {
        setTimeoutForSuspend(env, "Failed send request to " + targetServer);
        throw new ProcedureSuspendedException();
      }
    } finally {
      regionNode.unlock();
    }
  }
A remote procedure which is used to send region snapshot request to region server. The basic
logic of SnapshotRegionProcedure is similar like {@link ServerRemoteProcedure}, only with a
little difference, when {@link FailedRemoteDispatchException} was thrown, SnapshotRegionProcedure
will sleep some time and continue retrying until success.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/SnapshotRegionProcedure.java