public static ExchangeNode deserialize(ByteBuffer byteBuffer) {
    TEndPoint endPoint =
        new TEndPoint(
            ReadWriteIOUtils.readString(byteBuffer), ReadWriteIOUtils.readInt(byteBuffer));
    FragmentInstanceId fragmentInstanceId = FragmentInstanceId.deserialize(byteBuffer);
    PlanNodeId upstreamPlanNodeId = PlanNodeId.deserialize(byteBuffer);
    int outputColumnNamesSize = ReadWriteIOUtils.readInt(byteBuffer);
    List<String> outputColumnNames = new ArrayList<>(outputColumnNamesSize);
    while (outputColumnNamesSize > 0) {
      outputColumnNames.add(ReadWriteIOUtils.readString(byteBuffer));
      outputColumnNamesSize--;
    }
    int index = ReadWriteIOUtils.readInt(byteBuffer);
    PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer);
    ExchangeNode exchangeNode = new ExchangeNode(planNodeId);
    exchangeNode.setUpstream(endPoint, fragmentInstanceId, upstreamPlanNodeId);
    exchangeNode.setOutputColumnNames(outputColumnNames);
    exchangeNode.setIndexOfUpstreamSinkHandle(index);

    return exchangeNode;
  }
Exchange needs to know which child of IdentitySinkNode/ShuffleSinkNode it matches
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/ExchangeNode.java