@Override
  protected ProcedureLockState acquireLock(ConfigNodeProcedureEnv configNodeProcedureEnv) {
    LOGGER.info("ProcedureId {} try to acquire pipe lock.", getProcId());
    pipeTaskInfo = acquireLockInternal(configNodeProcedureEnv);
    if (pipeTaskInfo == null) {
      LOGGER.warn("ProcedureId {} failed to acquire pipe lock.", getProcId());
    } else {
      LOGGER.info("ProcedureId {} acquired pipe lock.", getProcId());
    }

    final ProcedureLockState procedureLockState = super.acquireLock(configNodeProcedureEnv);
    switch (procedureLockState) {
      case LOCK_ACQUIRED:
        if (pipeTaskInfo == null) {
          LOGGER.warn(
              "ProcedureId {}: LOCK_ACQUIRED. The following procedure should not be executed without pipe lock.",
              getProcId());
        } else {
          LOGGER.info(
              "ProcedureId {}: LOCK_ACQUIRED. The following procedure should be executed with pipe lock.",
              getProcId());
        }
        break;
      case LOCK_EVENT_WAIT:
        if (pipeTaskInfo == null) {
          LOGGER.warn("ProcedureId {}: LOCK_EVENT_WAIT. Without acquiring pipe lock.", getProcId());
        } else {
          LOGGER.info("ProcedureId {}: LOCK_EVENT_WAIT. Pipe lock will be released.", getProcId());
          configNodeProcedureEnv
              .getConfigManager()
              .getPipeManager()
              .getPipeTaskCoordinator()
              .unlock();
          pipeTaskInfo = null;
        }
        break;
      default:
        if (pipeTaskInfo == null) {
          LOGGER.error(
              "ProcedureId {}: {}. Invalid lock state. Without acquiring pipe lock.",
              getProcId(),
              procedureLockState);
        } else {
          LOGGER.error(
              "ProcedureId {}: {}. Invalid lock state. Pipe lock will be released.",
              getProcId(),
              procedureLockState);
          configNodeProcedureEnv
              .getConfigManager()
              .getPipeManager()
              .getPipeTaskCoordinator()
              .unlock();
          pipeTaskInfo = null;
        }
        break;
    }
    return procedureLockState;
  }
This procedure manages 2 kinds of PIPE operations:

<ul>
  <li>PIPE user task operations:
      <ul>
        <li>{@link PipeTaskOperation#CREATE_PIPE}
        <li>{@link PipeTaskOperation#START_PIPE}
        <li>{@link PipeTaskOperation#STOP_PIPE}
        <li>{@link PipeTaskOperation#DROP_PIPE}
        <li>{@link PipeTaskOperation#ALTER_PIPE}
      </ul>
  <li>PIPE runtime task operations:
      <ul>
        <li>{@link PipeTaskOperation#HANDLE_LEADER_CHANGE}
        <li>{@link PipeTaskOperation#SYNC_PIPE_META}
        <li>{@link PipeTaskOperation#HANDLE_PIPE_META_CHANGE}
      </ul>
</ul>

<p>This class extends {@link AbstractNodeProcedure} to make sure that pipe task procedures can be
executed in sequence and node procedures can be locked when a pipe task procedure is running.
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/pipe/AbstractOperatePipeProcedureV2.java