public static PipeRuntimeMeta deserializeVersion2(
      ByteBuffer byteBuffer, final boolean needPersist) {
    final PipeRuntimeMeta pipeRuntimeMeta = new PipeRuntimeMeta();

    pipeRuntimeMeta.status.set(PipeStatus.getPipeStatus(ReadWriteIOUtils.readByte(byteBuffer)));

    int size = ReadWriteIOUtils.readInt(byteBuffer);
    for (int i = 0; i < size; ++i) {
      final int taskIndex = ReadWriteIOUtils.readInt(byteBuffer);
      pipeRuntimeMeta.consensusGroupId2TaskMetaMap.put(
          taskIndex,
          PipeTaskMeta.deserialize(
              PipeRuntimeMetaVersion.VERSION_2, byteBuffer, taskIndex, needPersist));
    }

    size = ReadWriteIOUtils.readInt(byteBuffer);
    for (int i = 0; i < size; ++i) {
      pipeRuntimeMeta.nodeId2PipeRuntimeExceptionMap.put(
          ReadWriteIOUtils.readInt(byteBuffer),
          PipeRuntimeExceptionType.deserializeFrom(PipeRuntimeMetaVersion.VERSION_2, byteBuffer));
    }

    pipeRuntimeMeta.exceptionsClearTime.set(ReadWriteIOUtils.readLong(byteBuffer));
    pipeRuntimeMeta.isStoppedByRuntimeException.set(ReadWriteIOUtils.readBool(byteBuffer));

    return pipeRuntimeMeta;
  }
We use negative regionId to identify the external pipe source, which is not a consensus group
id. Then we can reuse the regionId to schedule the external pipe source and store the progress
information.
iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/task/meta/PipeRuntimeMeta.java