This is an automated email from the ASF dual-hosted git repository.

tanxinyu pushed a commit to branch rel/1.2
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/1.2 by this push:
     new f5e2c12744c add build info in show cluster (#10595) (#10700)
f5e2c12744c is described below

commit f5e2c12744c4ce3739d7cee9a5f23793aa257315
Author: YuFengLiu <[email protected]>
AuthorDate: Thu Jul 27 18:52:16 2023 +0800

    add build info in show cluster (#10595) (#10700)
---
 .../consensus/request/ConfigPhysicalPlan.java      |  4 +
 .../consensus/request/ConfigPhysicalPlanType.java  |  1 +
 .../write/confignode/ApplyConfigNodePlan.java      |  1 -
 ...onfigNodePlan.java => UpdateBuildInfoPlan.java} | 42 ++++++----
 .../iotdb/confignode/manager/ConfigManager.java    | 16 ++--
 .../iotdb/confignode/manager/ProcedureManager.java |  2 +-
 .../iotdb/confignode/manager/node/NodeManager.java | 55 ++++++++++---
 .../persistence/executor/ConfigPlanExecutor.java   |  3 +
 .../confignode/persistence/node/NodeInfo.java      | 93 ++++++++++++++++++++--
 .../procedure/env/ConfigNodeProcedureEnv.java      | 11 ++-
 .../impl/node/AddConfigNodeProcedure.java          | 19 ++++-
 .../iotdb/confignode/service/ConfigNode.java       | 80 +++++++++++--------
 .../impl/node/AddConfigNodeProcedureTest.java      |  4 +-
 .../common/header/ColumnHeaderConstant.java        |  3 +-
 .../execution/config/metadata/ShowClusterTask.java | 10 ++-
 .../java/org/apache/iotdb/db/service/DataNode.java |  2 +
 .../src/main/thrift/confignode.thrift              |  4 +
 17 files changed, 260 insertions(+), 90 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
index 2c0a3b59699..ffd7fc4c5f9 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
@@ -53,6 +53,7 @@ import 
org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerLoca
 import 
org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateBuildInfoPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.ActiveCQPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.AddCQPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.DropCQPlan;
@@ -280,6 +281,9 @@ public abstract class ConfigPhysicalPlan implements 
IConsensusRequest {
         case RemoveConfigNode:
           plan = new RemoveConfigNodePlan();
           break;
+        case UpdateBuildInfo:
+          plan = new UpdateBuildInfoPlan();
+          break;
         case CreateFunction:
           plan = new CreateFunctionPlan();
           break;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
index 46ae3e4bdc4..8644823b62b 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
@@ -27,6 +27,7 @@ public enum ConfigPhysicalPlanType {
   /** ConfigNode. */
   ApplyConfigNode((short) 0),
   RemoveConfigNode((short) 1),
+  UpdateBuildInfo((short) 2),
 
   /** DataNode. */
   RegisterDataNode((short) 100),
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
index 740c0fabfcc..ff674f57acc 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
@@ -50,7 +50,6 @@ public class ApplyConfigNodePlan extends ConfigPhysicalPlan {
   @Override
   protected void serializeImpl(DataOutputStream stream) throws IOException {
     ReadWriteIOUtils.write(getType().getPlanType(), stream);
-
     
ThriftConfigNodeSerDeUtils.serializeTConfigNodeLocation(configNodeLocation, 
stream);
   }
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/UpdateBuildInfoPlan.java
similarity index 63%
copy from 
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
copy to 
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/UpdateBuildInfoPlan.java
index 740c0fabfcc..8fdee39a5cf 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/ApplyConfigNodePlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/confignode/UpdateBuildInfoPlan.java
@@ -19,8 +19,6 @@
 
 package org.apache.iotdb.confignode.consensus.request.write.confignode;
 
-import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation;
-import org.apache.iotdb.commons.utils.ThriftConfigNodeSerDeUtils;
 import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan;
 import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
@@ -30,33 +28,40 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Objects;
 
-public class ApplyConfigNodePlan extends ConfigPhysicalPlan {
+public class UpdateBuildInfoPlan extends ConfigPhysicalPlan {
 
-  private TConfigNodeLocation configNodeLocation;
+  private int nodeId;
+  private String buildInfo;
 
-  public ApplyConfigNodePlan() {
-    super(ConfigPhysicalPlanType.ApplyConfigNode);
+  public UpdateBuildInfoPlan() {
+    super(ConfigPhysicalPlanType.UpdateBuildInfo);
   }
 
-  public ApplyConfigNodePlan(TConfigNodeLocation configNodeLocation) {
+  public UpdateBuildInfoPlan(String buildInfo, int nodeId) {
     this();
-    this.configNodeLocation = configNodeLocation;
+    this.buildInfo = buildInfo;
+    this.nodeId = nodeId;
   }
 
-  public TConfigNodeLocation getConfigNodeLocation() {
-    return configNodeLocation;
+  public String getBuildInfo() {
+    return buildInfo;
+  }
+
+  public int getNodeId() {
+    return nodeId;
   }
 
   @Override
   protected void serializeImpl(DataOutputStream stream) throws IOException {
     ReadWriteIOUtils.write(getType().getPlanType(), stream);
-
-    
ThriftConfigNodeSerDeUtils.serializeTConfigNodeLocation(configNodeLocation, 
stream);
+    ReadWriteIOUtils.write(nodeId, stream);
+    ReadWriteIOUtils.write(buildInfo, stream);
   }
 
   @Override
-  protected void deserializeImpl(ByteBuffer buffer) throws IOException {
-    configNodeLocation = 
ThriftConfigNodeSerDeUtils.deserializeTConfigNodeLocation(buffer);
+  protected void deserializeImpl(ByteBuffer buffer) {
+    nodeId = ReadWriteIOUtils.readInt(buffer);
+    buildInfo = ReadWriteIOUtils.readString(buffer);
   }
 
   @Override
@@ -67,12 +72,15 @@ public class ApplyConfigNodePlan extends ConfigPhysicalPlan 
{
     if (o == null || getClass() != o.getClass()) {
       return false;
     }
-    ApplyConfigNodePlan that = (ApplyConfigNodePlan) o;
-    return configNodeLocation.equals(that.configNodeLocation);
+    if (!getType().equals(((UpdateBuildInfoPlan) o).getType())) {
+      return false;
+    }
+    UpdateBuildInfoPlan that = (UpdateBuildInfoPlan) o;
+    return nodeId == that.nodeId && buildInfo.equals(that.buildInfo);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(configNodeLocation);
+    return Objects.hash(nodeId, buildInfo);
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index 06342cea9a7..69645b5061a 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -61,7 +61,6 @@ import 
org.apache.iotdb.confignode.consensus.request.write.database.SetDataRepli
 import 
org.apache.iotdb.confignode.consensus.request.write.database.SetSchemaReplicationFactorPlan;
 import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.database.SetTimePartitionIntervalPlan;
-import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RegisterDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RemoveDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.template.CreateSchemaTemplatePlan;
 import org.apache.iotdb.confignode.consensus.response.auth.PermissionInfoResp;
@@ -348,11 +347,9 @@ public class ConfigManager implements IManager {
               req.getDataNodeConfiguration().getLocation(),
               this);
       if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        return nodeManager.registerDataNode(
-            new RegisterDataNodePlan(req.getDataNodeConfiguration()));
+        return nodeManager.registerDataNode(req);
       }
     }
-
     DataNodeRegisterResp resp = new DataNodeRegisterResp();
     resp.setStatus(status);
     resp.setConfigNodeList(getNodeManager().getRegisteredConfigNodes());
@@ -375,7 +372,7 @@ public class ConfigManager implements IManager {
               req.getDataNodeConfiguration().getLocation(),
               this);
       if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        return 
nodeManager.updateDataNodeIfNecessary(req.getDataNodeConfiguration());
+        return nodeManager.updateDataNodeIfNecessary(req);
       }
     }
 
@@ -447,9 +444,12 @@ public class ConfigManager implements IManager {
               
.sorted(Comparator.comparingInt(TDataNodeLocation::getDataNodeId))
               .collect(Collectors.toList());
       Map<Integer, String> nodeStatus = 
getLoadManager().getNodeStatusWithReason();
-      return new TShowClusterResp(status, configNodeLocations, 
dataNodeInfoLocations, nodeStatus);
+      Map<Integer, String> nodeBuildInfo = getNodeManager().getNodeBuildInfo();
+      return new TShowClusterResp(
+          status, configNodeLocations, dataNodeInfoLocations, nodeStatus, 
nodeBuildInfo);
     } else {
-      return new TShowClusterResp(status, new ArrayList<>(), new 
ArrayList<>(), new HashMap<>());
+      return new TShowClusterResp(
+          status, new ArrayList<>(), new ArrayList<>(), new HashMap<>(), new 
HashMap<>());
     }
   }
 
@@ -1032,7 +1032,7 @@ public class ConfigManager implements IManager {
               req.getConfigNodeLocation(),
               this);
       if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        return nodeManager.restartConfigNode(req.getConfigNodeLocation());
+        return ClusterNodeStartUtils.ACCEPT_NODE_RESTART;
       }
     }
     return status;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
index 38c2630d41b..21f81248d7e 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
@@ -467,7 +467,7 @@ public class ProcedureManager {
    */
   public void addConfigNode(TConfigNodeRegisterReq req) {
     AddConfigNodeProcedure addConfigNodeProcedure =
-        new AddConfigNodeProcedure(req.getConfigNodeLocation());
+        new AddConfigNodeProcedure(req.getConfigNodeLocation(), 
req.getBuildInfo());
     this.executor.submitProcedure(addConfigNodeProcedure);
   }
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java
index b9fef9cba29..c34a5d54cdb 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java
@@ -40,6 +40,7 @@ import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import 
org.apache.iotdb.confignode.consensus.request.read.datanode.GetDataNodeConfigurationPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateBuildInfoPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RegisterDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RemoveDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.UpdateDataNodePlan;
@@ -65,6 +66,8 @@ import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterResp;
 import org.apache.iotdb.confignode.rpc.thrift.TDataNodeInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TDataNodeRegisterReq;
+import org.apache.iotdb.confignode.rpc.thrift.TDataNodeRestartReq;
 import org.apache.iotdb.confignode.rpc.thrift.TDataNodeRestartResp;
 import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
 import org.apache.iotdb.confignode.rpc.thrift.TRatisConfig;
@@ -73,6 +76,7 @@ import 
org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq;
 import org.apache.iotdb.consensus.common.DataSet;
 import org.apache.iotdb.consensus.common.Peer;
 import org.apache.iotdb.consensus.common.response.ConsensusGenericResponse;
+import org.apache.iotdb.consensus.common.response.ConsensusWriteResponse;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
@@ -234,17 +238,24 @@ public class NodeManager {
   /**
    * Register DataNode.
    *
-   * @param registerDataNodePlan RegisterDataNodeReq
+   * @param req TDataNodeRegisterReq
    * @return DataNodeConfigurationDataSet. The {@link TSStatus} will be set to 
{@link
    *     TSStatusCode#SUCCESS_STATUS} when register success.
    */
-  public DataSet registerDataNode(RegisterDataNodePlan registerDataNodePlan) {
+  public DataSet registerDataNode(TDataNodeRegisterReq req) {
     int dataNodeId = nodeInfo.generateNextNodeId();
 
+    RegisterDataNodePlan registerDataNodePlan =
+        new RegisterDataNodePlan(req.getDataNodeConfiguration());
     // Register new DataNode
     
registerDataNodePlan.getDataNodeConfiguration().getLocation().setDataNodeId(dataNodeId);
     getConsensusManager().write(registerDataNodePlan);
 
+    // update datanode's buildInfo
+    UpdateBuildInfoPlan updateBuildInfoPlan =
+        new UpdateBuildInfoPlan(req.getBuildInfo(), dataNodeId);
+    getConsensusManager().write(updateBuildInfoPlan);
+
     // Bind DataNode metrics
     PartitionMetrics.bindDataNodePartitionMetrics(
         MetricService.getInstance(), configManager, dataNodeId);
@@ -262,15 +273,21 @@ public class NodeManager {
     return resp;
   }
 
-  public TDataNodeRestartResp updateDataNodeIfNecessary(
-      TDataNodeConfiguration dataNodeConfiguration) {
-    TDataNodeConfiguration recordConfiguration =
-        
getRegisteredDataNode(dataNodeConfiguration.getLocation().getDataNodeId());
-    if (!recordConfiguration.equals(dataNodeConfiguration)) {
+  public TDataNodeRestartResp updateDataNodeIfNecessary(TDataNodeRestartReq 
req) {
+    int nodeId = req.getDataNodeConfiguration().getLocation().getDataNodeId();
+    TDataNodeConfiguration dataNodeConfiguration = 
getRegisteredDataNode(nodeId);
+    if (!req.getDataNodeConfiguration().equals(dataNodeConfiguration)) {
       // Update DataNodeConfiguration when modified during restart
-      UpdateDataNodePlan updateDataNodePlan = new 
UpdateDataNodePlan(dataNodeConfiguration);
+      UpdateDataNodePlan updateDataNodePlan =
+          new UpdateDataNodePlan(req.getDataNodeConfiguration());
       getConsensusManager().write(updateDataNodePlan);
     }
+    String recordBuildInfo = nodeInfo.getBuildInfo(nodeId);
+    if (!req.getBuildInfo().equals(recordBuildInfo)) {
+      // Update buildInfo when modified during restart
+      UpdateBuildInfoPlan updateBuildInfoPlan = new 
UpdateBuildInfoPlan(req.getBuildInfo(), nodeId);
+      getConsensusManager().write(updateBuildInfoPlan);
+    }
 
     TDataNodeRestartResp resp = new TDataNodeRestartResp();
     resp.setStatus(ClusterNodeStartUtils.ACCEPT_NODE_RESTART);
@@ -338,8 +355,14 @@ public class NodeManager {
         .setConfigNodeId(nodeId);
   }
 
-  public TSStatus restartConfigNode(TConfigNodeLocation configNodeLocation) {
-    // TODO: @Itami-Sho, update peer if necessary
+  public TSStatus updateConfigNodeIfNecessary(int configNodeId, String 
buildInfo) {
+    String recordBuildInfo = nodeInfo.getBuildInfo(configNodeId);
+    if (!recordBuildInfo.equals(buildInfo)) {
+      // Update buildInfo when modified during restart
+      UpdateBuildInfoPlan updateConfigNodePlan = new 
UpdateBuildInfoPlan(buildInfo, configNodeId);
+      ConsensusWriteResponse result = 
getConsensusManager().write(updateConfigNodePlan);
+      return result.getStatus();
+    }
     return ClusterNodeStartUtils.ACCEPT_NODE_RESTART;
   }
 
@@ -461,6 +484,10 @@ public class NodeManager {
     return nodeInfo.getRegisteredConfigNodes();
   }
 
+  public Map<Integer, String> getNodeBuildInfo() {
+    return nodeInfo.getNodeBuildInfo();
+  }
+
   public List<TConfigNodeInfo> getRegisteredConfigNodeInfoList() {
     List<TConfigNodeInfo> configNodeInfoList = new ArrayList<>();
     List<TConfigNodeLocation> registeredConfigNodes = 
this.getRegisteredConfigNodes();
@@ -487,11 +514,15 @@ public class NodeManager {
   /**
    * Only leader use this interface, record the new ConfigNode's information.
    *
-   * @param configNodeLocation The new ConfigNode
+   * @param configNodeLocation The new ConfigNode.
+   * @param buildInfo The new ConfigNode's buildInfo.
    */
-  public void applyConfigNode(TConfigNodeLocation configNodeLocation) {
+  public void applyConfigNode(TConfigNodeLocation configNodeLocation, String 
buildInfo) {
     ApplyConfigNodePlan applyConfigNodePlan = new 
ApplyConfigNodePlan(configNodeLocation);
     getConsensusManager().write(applyConfigNodePlan);
+    UpdateBuildInfoPlan updateBuildInfoPlan =
+        new UpdateBuildInfoPlan(buildInfo, 
configNodeLocation.getConfigNodeId());
+    getConsensusManager().write(updateBuildInfoPlan);
   }
 
   /**
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index e00466a8296..205eece1ca9 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -51,6 +51,7 @@ import 
org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerLoca
 import 
org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateBuildInfoPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.ActiveCQPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.AddCQPlan;
 import org.apache.iotdb.confignode.consensus.request.write.cq.DropCQPlan;
@@ -363,6 +364,8 @@ public class ConfigPlanExecutor {
         return nodeInfo.applyConfigNode((ApplyConfigNodePlan) physicalPlan);
       case RemoveConfigNode:
         return nodeInfo.removeConfigNode((RemoveConfigNodePlan) physicalPlan);
+      case UpdateBuildInfo:
+        return nodeInfo.updateBuildInfo((UpdateBuildInfoPlan) physicalPlan);
       case CreateFunction:
         return udfInfo.addUDFInTable((CreateFunctionPlan) physicalPlan);
       case DropFunction:
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/node/NodeInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/node/NodeInfo.java
index fe7a91a2789..d5300f8296c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/node/NodeInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/node/NodeInfo.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.confignode.conf.SystemPropertiesUtils;
 import 
org.apache.iotdb.confignode.consensus.request.read.datanode.GetDataNodeConfigurationPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateBuildInfoPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RegisterDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.RemoveDataNodePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.datanode.UpdateDataNodePlan;
@@ -86,9 +87,13 @@ public class NodeInfo implements SnapshotProcessor {
 
   // Registered DataNodes
   private final ReentrantReadWriteLock dataNodeInfoReadWriteLock;
+
+  private final ReentrantReadWriteLock buildInfoReadWriteLock;
+
   private final AtomicInteger nextNodeId = new AtomicInteger(-1);
   private final Map<Integer, TDataNodeConfiguration> registeredDataNodes;
 
+  private final Map<Integer, String> nodeBuildInfo;
   private static final String SNAPSHOT_FILENAME = "node_info.bin";
 
   public NodeInfo() {
@@ -97,6 +102,9 @@ public class NodeInfo implements SnapshotProcessor {
 
     this.dataNodeInfoReadWriteLock = new ReentrantReadWriteLock();
     this.registeredDataNodes = new ConcurrentHashMap<>();
+
+    this.nodeBuildInfo = new ConcurrentHashMap<>();
+    this.buildInfoReadWriteLock = new ReentrantReadWriteLock();
   }
 
   /**
@@ -120,7 +128,6 @@ public class NodeInfo implements SnapshotProcessor {
         }
       }
       registeredDataNodes.put(info.getLocation().getDataNodeId(), info);
-
       result = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
       if (nextNodeId.get() < MINIMUM_DATANODE) {
         result.setMessage(
@@ -149,14 +156,17 @@ public class NodeInfo implements SnapshotProcessor {
         registeredDataNodes.size());
 
     dataNodeInfoReadWriteLock.writeLock().lock();
+    buildInfoReadWriteLock.writeLock().lock();
     try {
       req.getDataNodeLocations()
           .forEach(
               removeDataNodes -> {
                 registeredDataNodes.remove(removeDataNodes.getDataNodeId());
+                nodeBuildInfo.remove(removeDataNodes.getDataNodeId());
                 LOGGER.info("Removed the datanode {} from cluster", 
removeDataNodes);
               });
     } finally {
+      buildInfoReadWriteLock.writeLock().unlock();
       dataNodeInfoReadWriteLock.writeLock().unlock();
     }
     LOGGER.info(
@@ -326,8 +336,10 @@ public class NodeInfo implements SnapshotProcessor {
   public TSStatus removeConfigNode(RemoveConfigNodePlan removeConfigNodePlan) {
     TSStatus status = new TSStatus();
     configNodeInfoReadWriteLock.writeLock().lock();
+    buildInfoReadWriteLock.writeLock().lock();
     try {
       
registeredConfigNodes.remove(removeConfigNodePlan.getConfigNodeLocation().getConfigNodeId());
+      
nodeBuildInfo.remove(removeConfigNodePlan.getConfigNodeLocation().getConfigNodeId());
       SystemPropertiesUtils.storeConfigNodeList(new 
ArrayList<>(registeredConfigNodes.values()));
       LOGGER.info(
           "Successfully remove ConfigNode: {}. Current ConfigNodeGroup: {}",
@@ -340,11 +352,29 @@ public class NodeInfo implements SnapshotProcessor {
       status.setMessage(
           "Remove ConfigNode failed because current ConfigNode can't store 
ConfigNode information.");
     } finally {
+      buildInfoReadWriteLock.writeLock().unlock();
       configNodeInfoReadWriteLock.writeLock().unlock();
     }
     return status;
   }
 
+  /**
+   * Update the specified Node‘s buildInfo.
+   *
+   * @param updateBuildInfoPlan UpdateBuildInfoPlan
+   * @return {@link TSStatusCode#SUCCESS_STATUS} if update build info 
successfully.
+   */
+  public TSStatus updateBuildInfo(UpdateBuildInfoPlan updateBuildInfoPlan) {
+    buildInfoReadWriteLock.writeLock().lock();
+    try {
+      nodeBuildInfo.put(updateBuildInfoPlan.getNodeId(), 
updateBuildInfoPlan.getBuildInfo());
+    } finally {
+      buildInfoReadWriteLock.writeLock().unlock();
+    }
+    LOGGER.info("Successfully update Node {} 's buildInfo.", 
updateBuildInfoPlan.getNodeId());
+    return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+  }
+
   /** @return All registered ConfigNodes. */
   public List<TConfigNodeLocation> getRegisteredConfigNodes() {
     List<TConfigNodeLocation> result;
@@ -374,6 +404,27 @@ public class NodeInfo implements SnapshotProcessor {
     return result;
   }
 
+  /** @return all nodes buildInfo */
+  public Map<Integer, String> getNodeBuildInfo() {
+    Map<Integer, String> result = new HashMap<>();
+    buildInfoReadWriteLock.readLock().lock();
+    try {
+      result.putAll(nodeBuildInfo);
+    } finally {
+      buildInfoReadWriteLock.readLock().unlock();
+    }
+    return result;
+  }
+
+  public String getBuildInfo(int nodeId) {
+    buildInfoReadWriteLock.readLock().lock();
+    try {
+      return nodeBuildInfo.getOrDefault(nodeId, "Unknown");
+    } finally {
+      buildInfoReadWriteLock.readLock().unlock();
+    }
+  }
+
   public int generateNextNodeId() {
     return nextNodeId.incrementAndGet();
   }
@@ -391,6 +442,7 @@ public class NodeInfo implements SnapshotProcessor {
     File tmpFile = new File(snapshotFile.getAbsolutePath() + "-" + 
UUID.randomUUID());
     configNodeInfoReadWriteLock.readLock().lock();
     dataNodeInfoReadWriteLock.readLock().lock();
+    buildInfoReadWriteLock.readLock().lock();
     try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
         TIOStreamTransport tioStreamTransport = new 
TIOStreamTransport(fileOutputStream)) {
 
@@ -402,6 +454,8 @@ public class NodeInfo implements SnapshotProcessor {
 
       serializeRegisteredDataNode(fileOutputStream, protocol);
 
+      serializeBuildInfo(fileOutputStream);
+
       fileOutputStream.flush();
 
       fileOutputStream.close();
@@ -409,8 +463,9 @@ public class NodeInfo implements SnapshotProcessor {
       return tmpFile.renameTo(snapshotFile);
 
     } finally {
-      configNodeInfoReadWriteLock.readLock().unlock();
+      buildInfoReadWriteLock.readLock().unlock();
       dataNodeInfoReadWriteLock.readLock().unlock();
+      configNodeInfoReadWriteLock.readLock().unlock();
       for (int retry = 0; retry < 5; retry++) {
         if (!tmpFile.exists() || tmpFile.delete()) {
           break;
@@ -440,6 +495,14 @@ public class NodeInfo implements SnapshotProcessor {
     }
   }
 
+  private void serializeBuildInfo(OutputStream outputStream) throws 
IOException {
+    ReadWriteIOUtils.write(nodeBuildInfo.size(), outputStream);
+    for (Entry<Integer, String> entry : nodeBuildInfo.entrySet()) {
+      ReadWriteIOUtils.write(entry.getKey(), outputStream);
+      ReadWriteIOUtils.write(entry.getValue(), outputStream);
+    }
+  }
+
   @Override
   public void processLoadSnapshot(File snapshotDir) throws IOException, 
TException {
 
@@ -453,6 +516,7 @@ public class NodeInfo implements SnapshotProcessor {
 
     configNodeInfoReadWriteLock.writeLock().lock();
     dataNodeInfoReadWriteLock.writeLock().lock();
+    buildInfoReadWriteLock.writeLock().lock();
 
     try (FileInputStream fileInputStream = new FileInputStream(snapshotFile);
         TIOStreamTransport tioStreamTransport = new 
TIOStreamTransport(fileInputStream)) {
@@ -466,9 +530,12 @@ public class NodeInfo implements SnapshotProcessor {
 
       deserializeRegisteredDataNode(fileInputStream, protocol);
 
+      deserializeBuildInfo(fileInputStream);
+
     } finally {
-      configNodeInfoReadWriteLock.writeLock().unlock();
+      buildInfoReadWriteLock.writeLock().unlock();
       dataNodeInfoReadWriteLock.writeLock().unlock();
+      configNodeInfoReadWriteLock.writeLock().unlock();
     }
   }
 
@@ -496,6 +563,20 @@ public class NodeInfo implements SnapshotProcessor {
     }
   }
 
+  private void deserializeBuildInfo(InputStream inputStream) throws 
IOException {
+    // old version may not have build info,
+    // thus we need to check inputStream before deserialize.
+    if (inputStream.available() != 0) {
+      int size = ReadWriteIOUtils.readInt(inputStream);
+      while (size > 0) {
+        int nodeId = ReadWriteIOUtils.readInt(inputStream);
+        String buildInfo = ReadWriteIOUtils.readString(inputStream);
+        nodeBuildInfo.put(nodeId, buildInfo);
+        size--;
+      }
+    }
+  }
+
   public static int getMinimumDataNode() {
     return MINIMUM_DATANODE;
   }
@@ -504,6 +585,7 @@ public class NodeInfo implements SnapshotProcessor {
     nextNodeId.set(-1);
     registeredDataNodes.clear();
     registeredConfigNodes.clear();
+    nodeBuildInfo.clear();
   }
 
   @Override
@@ -517,11 +599,12 @@ public class NodeInfo implements SnapshotProcessor {
     NodeInfo nodeInfo = (NodeInfo) o;
     return registeredConfigNodes.equals(nodeInfo.registeredConfigNodes)
         && nextNodeId.get() == nodeInfo.nextNodeId.get()
-        && registeredDataNodes.equals(nodeInfo.registeredDataNodes);
+        && registeredDataNodes.equals(nodeInfo.registeredDataNodes)
+        && nodeBuildInfo.equals(nodeInfo.nodeBuildInfo);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(registeredConfigNodes, nextNodeId, 
registeredDataNodes);
+    return Objects.hash(registeredConfigNodes, nextNodeId, 
registeredDataNodes, nodeBuildInfo);
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
index 77d573bf522..df6c32999b4 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
@@ -324,11 +324,18 @@ public class ConfigNodeProcedureEnv {
    * Leader will record the new ConfigNode's information.
    *
    * @param configNodeLocation The new ConfigNode
+   * @param buildInfo The new ConfigNode's buildInfo
    */
-  public void applyConfigNode(TConfigNodeLocation configNodeLocation) {
-    configManager.getNodeManager().applyConfigNode(configNodeLocation);
+  public void applyConfigNode(TConfigNodeLocation configNodeLocation, String 
buildInfo) {
+    configManager.getNodeManager().applyConfigNode(configNodeLocation, 
buildInfo);
   }
 
+  /**
+   * Leader will record the new Confignode's information.
+   *
+   * @param dataNodeConfiguration The new DataNode
+   */
+
   /**
    * Leader will notify the new ConfigNode that registration success.
    *
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedure.java
index 863a42952fe..d09d331e57d 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedure.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedure.java
@@ -26,6 +26,7 @@ import 
org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
 import org.apache.iotdb.confignode.procedure.exception.ProcedureException;
 import org.apache.iotdb.confignode.procedure.state.AddConfigNodeState;
 import org.apache.iotdb.confignode.procedure.store.ProcedureType;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,13 +43,16 @@ public class AddConfigNodeProcedure extends 
AbstractNodeProcedure<AddConfigNodeS
 
   private TConfigNodeLocation tConfigNodeLocation;
 
+  private String buildInfo;
+
   public AddConfigNodeProcedure() {
     super();
   }
 
-  public AddConfigNodeProcedure(TConfigNodeLocation tConfigNodeLocation) {
+  public AddConfigNodeProcedure(TConfigNodeLocation tConfigNodeLocation, 
String buildInfo) {
     super();
     this.tConfigNodeLocation = tConfigNodeLocation;
+    this.buildInfo = buildInfo;
   }
 
   @Override
@@ -75,7 +79,7 @@ public class AddConfigNodeProcedure extends 
AbstractNodeProcedure<AddConfigNodeS
           break;
         case REGISTER_SUCCESS:
           env.notifyRegisterSuccess(tConfigNodeLocation);
-          env.applyConfigNode(tConfigNodeLocation);
+          env.applyConfigNode(tConfigNodeLocation, buildInfo);
           env.broadCastTheLatestConfigNodeGroup();
           LOG.info("The ConfigNode: {} is successfully added to the cluster", 
tConfigNodeLocation);
           return Flow.NO_MORE_STATE;
@@ -145,6 +149,7 @@ public class AddConfigNodeProcedure extends 
AbstractNodeProcedure<AddConfigNodeS
     stream.writeShort(ProcedureType.ADD_CONFIG_NODE_PROCEDURE.getTypeCode());
     super.serialize(stream);
     
ThriftConfigNodeSerDeUtils.serializeTConfigNodeLocation(tConfigNodeLocation, 
stream);
+    ReadWriteIOUtils.write(buildInfo, stream);
   }
 
   @Override
@@ -152,6 +157,11 @@ public class AddConfigNodeProcedure extends 
AbstractNodeProcedure<AddConfigNodeS
     super.deserialize(byteBuffer);
     try {
       tConfigNodeLocation = 
ThriftConfigNodeSerDeUtils.deserializeTConfigNodeLocation(byteBuffer);
+      // old version may not have build info,
+      // thus we need to check inputStream before deserialize.
+      if (byteBuffer.hasRemaining()) {
+        buildInfo = ReadWriteIOUtils.readString(byteBuffer);
+      }
     } catch (ThriftSerDeException e) {
       LOG.error("Error in deserialize AddConfigNodeProcedure", e);
     }
@@ -163,13 +173,14 @@ public class AddConfigNodeProcedure extends 
AbstractNodeProcedure<AddConfigNodeS
       AddConfigNodeProcedure thatProc = (AddConfigNodeProcedure) that;
       return thatProc.getProcId() == this.getProcId()
           && thatProc.getState() == this.getState()
-          && thatProc.tConfigNodeLocation.equals(this.tConfigNodeLocation);
+          && thatProc.tConfigNodeLocation.equals(this.tConfigNodeLocation)
+          && thatProc.buildInfo.equals(this.buildInfo);
     }
     return false;
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(this.tConfigNodeLocation);
+    return Objects.hash(this.tConfigNodeLocation, this.buildInfo);
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
index 073a95aa034..39a93cdb2bb 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
@@ -122,12 +122,17 @@ public class ConfigNode implements ConfigNodeMBean {
       if (SystemPropertiesUtils.isRestarted()) {
         LOGGER.info("{} is in restarting process...", 
ConfigNodeConstant.GLOBAL_NAME);
 
+        int configNodeId;
         if (!SystemPropertiesUtils.isSeedConfigNode()) {
-          // The non-seed-ConfigNodes should send restart request
+          // The non-seed-ConfigNodes should send restart request and be 
checked (ip and port) by
+          // leader before initConsensusManager
           sendRestartConfigNodeRequest();
+          configNodeId = CONF.getConfigNodeId();
+        } else {
+          configNodeId = SEED_CONFIG_NODE_ID;
         }
-
         configManager.initConsensusManager();
+
         setUpMetricService();
         // Notice: We always set up Seed-ConfigNode's RPC service lastly to 
ensure
         // that the external service is not provided until ConfigNode is fully 
available
@@ -137,6 +142,20 @@ public class ConfigNode implements ConfigNodeMBean {
             "{} has successfully restarted and joined the cluster: {}.",
             ConfigNodeConstant.GLOBAL_NAME,
             CONF.getClusterName());
+
+        // Update item during restart
+        // This will always be executed until the consensus write succeeds
+        while (true) {
+          TSStatus status =
+              configManager
+                  .getNodeManager()
+                  .updateConfigNodeIfNecessary(configNodeId, 
IoTDBConstant.BUILD_INFO);
+          if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) 
{
+            break;
+          } else {
+            startUpSleep("restart ConfigNode failed! ");
+          }
+        }
         return;
       }
 
@@ -158,10 +177,7 @@ public class ConfigNode implements ConfigNodeMBean {
         configManager
             .getNodeManager()
             .applyConfigNode(
-                new TConfigNodeLocation(
-                    SEED_CONFIG_NODE_ID,
-                    new TEndPoint(CONF.getInternalAddress(), 
CONF.getInternalPort()),
-                    new TEndPoint(CONF.getInternalAddress(), 
CONF.getConsensusPort())));
+                generateConfigNodeLocation(SEED_CONFIG_NODE_ID), 
IoTDBConstant.BUILD_INFO);
         setUpMetricService();
         // Notice: We always set up Seed-ConfigNode's RPC service lastly to 
ensure
         // that the external service is not provided until Seed-ConfigNode is 
fully initialized
@@ -200,13 +216,7 @@ public class ConfigNode implements ConfigNodeMBean {
           isJoinedCluster = true;
           break;
         }
-
-        try {
-          TimeUnit.MILLISECONDS.sleep(STARTUP_RETRY_INTERVAL_IN_MS);
-        } catch (InterruptedException e) {
-          LOGGER.warn("Waiting leader's scheduling is interrupted.");
-          Thread.currentThread().interrupt();
-        }
+        startUpSleep("Waiting leader's scheduling is interrupted.");
       }
 
       if (!isJoinedCluster) {
@@ -294,10 +304,9 @@ public class ConfigNode implements ConfigNodeMBean {
     TConfigNodeRegisterReq req =
         new TConfigNodeRegisterReq(
             configManager.getClusterParameters(),
-            new TConfigNodeLocation(
-                INIT_NON_SEED_CONFIG_NODE_ID,
-                new TEndPoint(CONF.getInternalAddress(), 
CONF.getInternalPort()),
-                new TEndPoint(CONF.getInternalAddress(), 
CONF.getConsensusPort())));
+            generateConfigNodeLocation(INIT_NON_SEED_CONFIG_NODE_ID));
+
+    req.setBuildInfo(IoTDBConstant.BUILD_INFO);
 
     TEndPoint targetConfigNode = CONF.getTargetConfigNode();
     if (targetConfigNode == null) {
@@ -336,13 +345,7 @@ public class ConfigNode implements ConfigNodeMBean {
       } else {
         throw new StartupException(status.getMessage());
       }
-
-      try {
-        TimeUnit.MILLISECONDS.sleep(STARTUP_RETRY_INTERVAL_IN_MS);
-      } catch (InterruptedException e) {
-        Thread.currentThread().interrupt();
-        throw new StartupException("Register ConfigNode failed!");
-      }
+      startUpSleep("Register ConfigNode failed!");
     }
 
     LOGGER.error(
@@ -351,13 +354,10 @@ public class ConfigNode implements ConfigNodeMBean {
   }
 
   private void sendRestartConfigNodeRequest() throws StartupException {
+
     TConfigNodeRestartReq req =
         new TConfigNodeRestartReq(
-            CONF.getClusterName(),
-            new TConfigNodeLocation(
-                CONF.getConfigNodeId(),
-                new TEndPoint(CONF.getInternalAddress(), 
CONF.getInternalPort()),
-                new TEndPoint(CONF.getInternalAddress(), 
CONF.getConsensusPort())));
+            CONF.getClusterName(), 
generateConfigNodeLocation(CONF.getConfigNodeId()));
 
     TEndPoint targetConfigNode = CONF.getTargetConfigNode();
     if (targetConfigNode == null) {
@@ -382,13 +382,23 @@ public class ConfigNode implements ConfigNodeMBean {
       } else {
         throw new StartupException(status.getMessage());
       }
+      startUpSleep("Register ConfigNode failed! ");
+    }
+  }
 
-      try {
-        TimeUnit.MILLISECONDS.sleep(STARTUP_RETRY_INTERVAL_IN_MS);
-      } catch (InterruptedException e) {
-        Thread.currentThread().interrupt();
-        throw new StartupException("Register ConfigNode failed! ");
-      }
+  private TConfigNodeLocation generateConfigNodeLocation(int configNodeId) {
+    return new TConfigNodeLocation(
+        configNodeId,
+        new TEndPoint(CONF.getInternalAddress(), CONF.getInternalPort()),
+        new TEndPoint(CONF.getInternalAddress(), CONF.getConsensusPort()));
+  }
+
+  private void startUpSleep(String errorMessage) throws StartupException {
+    try {
+      TimeUnit.MILLISECONDS.sleep(STARTUP_RETRY_INTERVAL_IN_MS);
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new StartupException(errorMessage);
     }
   }
 
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedureTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedureTest.java
index e7d2b05dc82..d95d49c6aa2 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedureTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedureTest.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.confignode.procedure.impl.node;
 
 import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TEndPoint;
+import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.confignode.procedure.store.ProcedureFactory;
 import org.apache.iotdb.tsfile.utils.PublicBAOS;
 
@@ -37,7 +38,8 @@ public class AddConfigNodeProcedureTest {
     AddConfigNodeProcedure procedure0 =
         new AddConfigNodeProcedure(
             new TConfigNodeLocation(
-                0, new TEndPoint("127.0.0.1", 10710), new TEndPoint("0.0.0.0", 
10720)));
+                0, new TEndPoint("127.0.0.1", 10710), new TEndPoint("0.0.0.0", 
10720)),
+            IoTDBConstant.BUILD_INFO);
 
     try (PublicBAOS byteArrayOutputStream = new PublicBAOS();
         DataOutputStream outputStream = new 
DataOutputStream(byteArrayOutputStream)) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java
index 66abe3abc20..7035a2bbd3d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java
@@ -329,7 +329,8 @@ public class ColumnHeaderConstant {
           new ColumnHeader(NODE_TYPE, TSDataType.TEXT),
           new ColumnHeader(STATUS, TSDataType.TEXT),
           new ColumnHeader(INTERNAL_ADDRESS, TSDataType.TEXT),
-          new ColumnHeader(INTERNAL_PORT, TSDataType.INT32));
+          new ColumnHeader(INTERNAL_PORT, TSDataType.INT32),
+          new ColumnHeader(BUILD_INFO, TSDataType.TEXT));
 
   public static final List<ColumnHeader> showClusterDetailsColumnHeaders =
       ImmutableList.of(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowClusterTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowClusterTask.java
index f59e064c2f5..71db942031c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowClusterTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/ShowClusterTask.java
@@ -62,13 +62,15 @@ public class ShowClusterTask implements IConfigTask {
       String nodeType,
       String nodeStatus,
       String hostAddress,
-      int port) {
+      int port,
+      String buildInfo) {
     builder.getTimeColumnBuilder().writeLong(0L);
     builder.getColumnBuilder(0).writeInt(nodeId);
     builder.getColumnBuilder(1).writeBinary(new Binary(nodeType));
     builder.getColumnBuilder(2).writeBinary(new Binary(nodeStatus));
     builder.getColumnBuilder(3).writeBinary(new Binary(hostAddress));
     builder.getColumnBuilder(4).writeInt(port);
+    builder.getColumnBuilder(5).writeBinary(new Binary(buildInfo));
     builder.declarePosition();
   }
 
@@ -90,7 +92,8 @@ public class ShowClusterTask implements IConfigTask {
                     NODE_TYPE_CONFIG_NODE,
                     clusterNodeInfos.getNodeStatus().get(e.getConfigNodeId()),
                     e.getInternalEndPoint().getIp(),
-                    e.getInternalEndPoint().getPort()));
+                    e.getInternalEndPoint().getPort(),
+                    
clusterNodeInfos.getNodeBuildInfo().get(e.getConfigNodeId())));
 
     clusterNodeInfos
         .getDataNodeList()
@@ -102,7 +105,8 @@ public class ShowClusterTask implements IConfigTask {
                     NODE_TYPE_DATA_NODE,
                     clusterNodeInfos.getNodeStatus().get(e.getDataNodeId()),
                     e.getInternalEndPoint().getIp(),
-                    e.getInternalEndPoint().getPort()));
+                    e.getInternalEndPoint().getPort(),
+                    
clusterNodeInfos.getNodeBuildInfo().get(e.getDataNodeId())));
 
     DatasetHeader datasetHeader = DatasetHeaderFactory.getShowClusterHeader();
     future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS, 
builder.build(), datasetHeader));
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
index f59b3dc4bae..fce5216b9c5 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java
@@ -361,6 +361,7 @@ public class DataNode implements DataNodeMBean {
     TDataNodeRegisterReq req = new TDataNodeRegisterReq();
     req.setDataNodeConfiguration(generateDataNodeConfiguration());
     req.setClusterName(config.getClusterName());
+    req.setBuildInfo(IoTDBConstant.BUILD_INFO);
     TDataNodeRegisterResp dataNodeRegisterResp = null;
     while (retry > 0) {
       try (ConfigNodeClient configNodeClient =
@@ -420,6 +421,7 @@ public class DataNode implements DataNodeMBean {
     req.setClusterName(
         config.getClusterName() == null ? DEFAULT_CLUSTER_NAME : 
config.getClusterName());
     req.setDataNodeConfiguration(generateDataNodeConfiguration());
+    req.setBuildInfo(IoTDBConstant.BUILD_INFO);
     TDataNodeRestartResp dataNodeRestartResp = null;
     while (retry > 0) {
       try (ConfigNodeClient configNodeClient =
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift 
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index e0057bd09db..b4b8cd9e379 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -102,6 +102,7 @@ struct TRuntimeConfiguration {
 struct TDataNodeRegisterReq {
   1: required string clusterName
   2: required common.TDataNodeConfiguration dataNodeConfiguration
+  3: optional string buildInfo = "Unknown"
 }
 
 struct TDataNodeRegisterResp {
@@ -114,6 +115,7 @@ struct TDataNodeRegisterResp {
 struct TDataNodeRestartReq {
   1: required string clusterName
   2: required common.TDataNodeConfiguration dataNodeConfiguration
+  3: optional string buildInfo = "Unknown"
 }
 
 struct TDataNodeRestartResp {
@@ -366,6 +368,7 @@ struct TConfigNodeRegisterReq {
   // fields are consistent with the Seed-ConfigNode
   1: required TClusterParameters clusterParameters
   2: required common.TConfigNodeLocation configNodeLocation
+  3: optional string buildInfo = "Unknown"
 }
 
 struct TConfigNodeRegisterResp {
@@ -483,6 +486,7 @@ struct TShowClusterResp {
   2: required list<common.TConfigNodeLocation> configNodeList
   3: required list<common.TDataNodeLocation> dataNodeList
   4: required map<i32, string> nodeStatus
+  5: required map<i32, string> nodeBuildInfo
 }
 
 struct TShowVariablesResp {

Reply via email to