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

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


The following commit(s) were added to refs/heads/dev/1.3 by this push:
     new b49e617f2fa [To dev/1.3][remove confignode] Add Remove ConfigNode SQL 
(#14854)
b49e617f2fa is described below

commit b49e617f2fa70ff91e01d5f78cdada7e3b3edd04
Author: Xiangpeng Hu <[email protected]>
AuthorDate: Sat Feb 15 15:28:42 2025 +0800

    [To dev/1.3][remove confignode] Add Remove ConfigNode SQL (#14854)
    
    * [remove confignode] Add Remove ConfigNode SQL (#14813)
    
    * add remove ConfigNode
    
    * add IT
    
    * removeConfigNodeNum
    
    (cherry picked from commit 6233e53acd42d7271aeba5510b90b10ed6e9bc24)
    
    * resolve conflicts
---
 .../IoTDBRemoveConfigNodeITFramework.java          | 199 +++++++++++++++++++++
 .../IoTDBRemoveConfigNodeNormalIT.java             |  37 ++++
 .../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 |   1 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   7 +-
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |   4 +
 .../iotdb/db/protocol/client/ConfigNodeClient.java |   3 +-
 .../plan/execution/config/ConfigTaskVisitor.java   |   8 +
 .../config/executor/ClusterConfigTaskExecutor.java |  45 +++++
 .../config/executor/IConfigTaskExecutor.java       |   4 +
 .../config/metadata/RemoveConfigNodeTask.java      |  43 +++++
 .../db/queryengine/plan/parser/ASTVisitor.java     |   7 +
 .../plan/statement/StatementVisitor.java           |   5 +
 .../metadata/RemoveConfigNodeStatement.java        |  71 ++++++++
 13 files changed, 432 insertions(+), 2 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeITFramework.java
 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeITFramework.java
new file mode 100644
index 00000000000..561e99ec3da
--- /dev/null
+++ 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeITFramework.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.confignode.it.removeconfignode;
+
+import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient;
+import org.apache.iotdb.confignode.it.removedatanode.SQLModel;
+import org.apache.iotdb.consensus.ConsensusFactory;
+import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.exception.InconsistentDataException;
+import org.apache.iotdb.jdbc.IoTDBSQLException;
+
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionTimeoutException;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static 
org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework.getDataRegionMap;
+import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly;
+
+public class IoTDBRemoveConfigNodeITFramework {
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(IoTDBRemoveConfigNodeITFramework.class);
+  private static final String TREE_MODEL_INSERTION =
+      "INSERT INTO root.sg.d1(timestamp,speed,temperature) values(100, 1, 2)";
+
+  private static final String SHOW_CONFIGNODES = "show confignodes";
+
+  private static final String defaultSchemaRegionGroupExtensionPolicy = 
"CUSTOM";
+  private static final String defaultDataRegionGroupExtensionPolicy = "CUSTOM";
+
+  @Before
+  public void setUp() throws Exception {
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setConfigNodeConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS)
+        
.setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS)
+        .setDataRegionConsensusProtocolClass(ConsensusFactory.IOT_CONSENSUS)
+        
.setSchemaRegionGroupExtensionPolicy(defaultSchemaRegionGroupExtensionPolicy)
+        
.setDataRegionGroupExtensionPolicy(defaultDataRegionGroupExtensionPolicy);
+  }
+
+  @After
+  public void tearDown() throws InterruptedException {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  public void testRemoveConfigNode(
+      final int dataReplicateFactor,
+      final int schemaReplicationFactor,
+      final int configNodeNum,
+      final int dataNodeNum,
+      final int dataRegionPerDataNode,
+      final SQLModel model)
+      throws Exception {
+
+    // Set up the environment
+    EnvFactory.getEnv()
+        .getConfig()
+        .getCommonConfig()
+        .setSchemaReplicationFactor(schemaReplicationFactor)
+        .setDataReplicationFactor(dataReplicateFactor)
+        .setDefaultDataRegionGroupNumPerDatabase(
+            dataRegionPerDataNode * dataNodeNum / dataReplicateFactor);
+    EnvFactory.getEnv().initClusterEnvironment(configNodeNum, dataNodeNum);
+
+    try (final Connection connection = 
makeItCloseQuietly(EnvFactory.getEnv().getConnection());
+        final Statement statement = 
makeItCloseQuietly(connection.createStatement());
+        SyncConfigNodeIServiceClient client =
+            (SyncConfigNodeIServiceClient) 
EnvFactory.getEnv().getLeaderConfigNodeConnection()) {
+
+      // Insert data in tree model
+      statement.execute(TREE_MODEL_INSERTION);
+
+      Map<Integer, Set<Integer>> regionMap = getDataRegionMap(statement);
+      regionMap.forEach(
+          (key, valueSet) -> {
+            LOGGER.info("Key: {}, Value: {}", key, valueSet);
+            if (valueSet.size() != dataReplicateFactor) {
+              Assert.fail();
+            }
+          });
+
+      // Get all config nodes
+      ResultSet result = statement.executeQuery(SHOW_CONFIGNODES);
+      Set<Integer> allConfigNodeId = new HashSet<>();
+      while (result.next()) {
+        allConfigNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID));
+      }
+
+      AtomicReference<SyncConfigNodeIServiceClient> clientRef = new 
AtomicReference<>(client);
+
+      int removeConfigNodeId = allConfigNodeId.iterator().next();
+      String removeConfigNodeSQL = generateRemoveString(removeConfigNodeId);
+      LOGGER.info("Remove ConfigNodes SQL: {}", removeConfigNodeSQL);
+      try {
+        statement.execute(removeConfigNodeSQL);
+      } catch (IoTDBSQLException e) {
+        LOGGER.error("Remove ConfigNodes SQL execute fail: {}", 
e.getMessage());
+        Assert.fail();
+      }
+      LOGGER.info("Remove ConfigNodes SQL submit successfully.");
+
+      // Wait until success
+      try {
+        awaitUntilSuccess(statement, removeConfigNodeId);
+      } catch (ConditionTimeoutException e) {
+        LOGGER.error("Remove ConfigNodes timeout in 2 minutes");
+        Assert.fail();
+      }
+
+      LOGGER.info("Remove ConfigNodes success");
+    } catch (InconsistentDataException e) {
+      LOGGER.error("Unexpected error:", e);
+    }
+  }
+
+  private static void awaitUntilSuccess(Statement statement, int 
removeConfigNodeId) {
+    AtomicReference<Set<Integer>> lastTimeConfigNodes = new 
AtomicReference<>();
+    AtomicReference<Exception> lastException = new AtomicReference<>();
+
+    try {
+      Awaitility.await()
+          .atMost(2, TimeUnit.MINUTES)
+          .pollDelay(2, TimeUnit.SECONDS)
+          .until(
+              () -> {
+                try {
+                  // Get all config nodes
+                  ResultSet result = statement.executeQuery(SHOW_CONFIGNODES);
+                  Set<Integer> allConfigNodeId = new HashSet<>();
+                  while (result.next()) {
+                    
allConfigNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID));
+                  }
+                  lastTimeConfigNodes.set(allConfigNodeId);
+                  return !allConfigNodeId.contains(removeConfigNodeId);
+                } catch (Exception e) {
+                  // Any exception can be ignored
+                  lastException.set(e);
+                  return false;
+                }
+              });
+    } catch (ConditionTimeoutException e) {
+      if (lastTimeConfigNodes.get() == null) {
+        LOGGER.error(
+            "Maybe show confignodes fail, lastTimeConfigNodes is null, last 
Exception:",
+            lastException.get());
+        throw e;
+      }
+      String actualSetStr = lastTimeConfigNodes.get().toString();
+      lastTimeConfigNodes.get().remove(removeConfigNodeId);
+      String expectedSetStr = lastTimeConfigNodes.get().toString();
+      LOGGER.error(
+          "Remove ConfigNode timeout in 2 minutes, expected set: {}, actual 
set: {}",
+          expectedSetStr,
+          actualSetStr);
+      if (lastException.get() == null) {
+        LOGGER.info("No exception during awaiting");
+      } else {
+        LOGGER.error("Last exception during awaiting:", lastException.get());
+      }
+      throw e;
+    }
+  }
+
+  public static String generateRemoveString(Integer configNodeId) {
+    return "remove confignode " + configNodeId;
+  }
+}
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeNormalIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeNormalIT.java
new file mode 100644
index 00000000000..44a1100672e
--- /dev/null
+++ 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removeconfignode/IoTDBRemoveConfigNodeNormalIT.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.confignode.it.removeconfignode;
+
+import org.apache.iotdb.confignode.it.removedatanode.SQLModel;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+@Category({ClusterIT.class})
+@RunWith(IoTDBTestRunner.class)
+public class IoTDBRemoveConfigNodeNormalIT extends 
IoTDBRemoveConfigNodeITFramework {
+  @Test
+  public void test3C1DUseTreeSQL() throws Exception {
+    testRemoveConfigNode(1, 1, 3, 1, 2, SQLModel.TREE_MODEL_SQL);
+  }
+}
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index b1a785a8ef8..04f603857a4 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -62,6 +62,7 @@ keyWords
     | CLUSTERID
     | CONCAT
     | CONDITION
+    | CONFIGNODE
     | CONFIGNODES
     | CONFIGURATION
     | CONNECTION
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 64136c76493..8c7fe4264fd 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -65,7 +65,7 @@ ddlStatement
     // Cluster
     | showVariables | showCluster | showRegions | showDataNodes | 
showConfigNodes | showClusterId
     | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList
-    | migrateRegion | reconstructRegion | extendRegion | removeRegion  | 
removeDataNode
+    | migrateRegion | reconstructRegion | extendRegion | removeRegion  | 
removeDataNode | removeConfigNode
     | verifyConnection
     // AINode
     | showAINodes | createModel | dropModel | showModels | callInference
@@ -559,6 +559,11 @@ removeDataNode
     : REMOVE DATANODE dataNodeId=INTEGER_LITERAL (COMMA 
dataNodeId=INTEGER_LITERAL)*
     ;
 
+// ---- Remove ConfigNode
+removeConfigNode
+    : REMOVE CONFIGNODE configNodeId=INTEGER_LITERAL
+    ;
+
 // Pipe Task 
=========================================================================================
 createPipe
     : CREATE PIPE  (IF NOT EXISTS)? pipeName=identifier
diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 556dfebb48b..10d0da69de4 100644
--- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -165,6 +165,10 @@ CONFIGNODES
     : C O N F I G N O D E S
     ;
 
+CONFIGNODE
+    : C O N F I G N O D E
+    ;
+
 CONFIGURATION
     : C O N F I G U R A T I O N
     ;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
index 82e9d231066..6585c39cf6a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
@@ -692,7 +692,8 @@ public class ConfigNodeClient implements 
IConfigNodeRPCService.Iface, ThriftClie
 
   @Override
   public TSStatus removeConfigNode(TConfigNodeLocation configNodeLocation) 
throws TException {
-    throw new TException("DataNode to ConfigNode client doesn't support 
removeConfigNode.");
+    return executeRemoteCallWithRetry(
+        () -> client.removeConfigNode(configNodeLocation), resp -> 
!updateConfigNodeLeader(resp));
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java
index 347f44c2fe0..21caaa6e25f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.DropTrigge
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetRegionIdTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetSeriesSlotListTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.GetTimeSlotListTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveConfigNodeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.RemoveDataNodeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.SetTTLTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterDetailsTask;
@@ -115,6 +116,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DropTriggerStatem
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement;
@@ -615,6 +617,12 @@ public class ConfigTaskVisitor extends 
StatementVisitor<IConfigTask, MPPQueryCon
     return new RemoveDataNodeTask(removeDataNodeStatement);
   }
 
+  @Override
+  public IConfigTask visitRemoveConfigNode(
+      RemoveConfigNodeStatement removeConfigNodeStatement, MPPQueryContext 
context) {
+    return new RemoveConfigNodeTask(removeConfigNodeStatement);
+  }
+
   @Override
   public IConfigTask visitCreateContinuousQuery(
       CreateContinuousQueryStatement createContinuousQueryStatement, 
MPPQueryContext context) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index 7402a9b99e2..a26185b832c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.queryengine.plan.execution.config.executor;
 
+import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeConfiguration;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TFlushReq;
@@ -188,6 +189,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DeleteTimeSeriesS
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
@@ -2735,6 +2737,49 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
     return future;
   }
 
+  @Override
+  public SettableFuture<ConfigTaskResult> removeConfigNode(
+      final RemoveConfigNodeStatement removeConfigNodeStatement) {
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+
+    int removeConfigNodeId = removeConfigNodeStatement.getNodeId();
+
+    LOGGER.info("Starting to remove ConfigNode with node-id {}", 
removeConfigNodeId);
+    try (ConfigNodeClient configNodeClient =
+        
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
+
+      TShowClusterResp showClusterResp = configNodeClient.showCluster();
+      List<TConfigNodeLocation> removeConfigNodeLocations =
+          showClusterResp.getConfigNodeList().stream()
+              .filter(node -> node.configNodeId == removeConfigNodeId)
+              .collect(Collectors.toList());
+      if (removeConfigNodeLocations.size() != 1) {
+        LOGGER.error(
+            "The ConfigNode to be removed is not in the cluster, or the input 
format is incorrect.");
+        future.set(new ConfigTaskResult(TSStatusCode.REMOVE_CONFIGNODE_ERROR));
+      }
+
+      TConfigNodeLocation configNodeLocation = 
removeConfigNodeLocations.get(0);
+      TSStatus status = configNodeClient.removeConfigNode(configNodeLocation);
+
+      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        future.setException(new IOException("Remove ConfigNode failed: " + 
status.getMessage()));
+        return future;
+      } else {
+        LOGGER.info(
+            "ConfigNode: {} is removed. If the confignode data directory is no 
longer needed, you can delete it manually.",
+            removeConfigNodeId);
+        future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS));
+      }
+
+    } catch (Exception e) {
+      future.setException(e);
+      return future;
+    }
+
+    return future;
+  }
+
   @Override
   public SettableFuture<ConfigTaskResult> reconstructRegion(
       ReconstructRegionStatement reconstructRegionStatement) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
index ce6f8868e6c..e05457d9cf8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -39,6 +39,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DeleteTimeSeriesS
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement;
@@ -236,6 +237,9 @@ public interface IConfigTaskExecutor {
 
   SettableFuture<ConfigTaskResult> removeDataNode(RemoveDataNodeStatement 
removeDataNodeStatement);
 
+  SettableFuture<ConfigTaskResult> removeConfigNode(
+      RemoveConfigNodeStatement removeConfigNodeStatement);
+
   SettableFuture<ConfigTaskResult> createContinuousQuery(
       CreateContinuousQueryStatement createContinuousQueryStatement, 
MPPQueryContext context);
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/RemoveConfigNodeTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/RemoveConfigNodeTask.java
new file mode 100644
index 00000000000..aa11f7fad52
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/RemoveConfigNodeTask.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.execution.config.metadata;
+
+import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
+import org.apache.iotdb.db.queryengine.plan.execution.config.IConfigTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.IConfigTaskExecutor;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class RemoveConfigNodeTask implements IConfigTask {
+
+  protected final RemoveConfigNodeStatement statement;
+
+  public RemoveConfigNodeTask(RemoveConfigNodeStatement 
removeConfigNodeStatement) {
+    this.statement = removeConfigNodeStatement;
+  }
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(IConfigTaskExecutor 
configTaskExecutor) {
+    // If the action is executed successfully, return the Future.
+    // If your operation is async, you can return the corresponding future 
directly.
+    return configTaskExecutor.removeConfigNode(statement);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
index c86af7cfb38..420e117af73 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java
@@ -148,6 +148,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DropTriggerStatem
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
@@ -4179,6 +4180,12 @@ public class ASTVisitor extends 
IoTDBSqlParserBaseVisitor<Statement> {
     return new RemoveDataNodeStatement(dataNodeIDs);
   }
 
+  @Override
+  public Statement 
visitRemoveConfigNode(IoTDBSqlParser.RemoveConfigNodeContext ctx) {
+    Integer nodeId = Integer.parseInt(ctx.INTEGER_LITERAL().getText());
+    return new RemoveConfigNodeStatement(nodeId);
+  }
+
   @Override
   public Statement 
visitVerifyConnection(IoTDBSqlParser.VerifyConnectionContext ctx) {
     return new TestConnectionStatement(ctx.DETAILS() != null);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
index 333d21aeccd..7af95f40a9a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java
@@ -55,6 +55,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.DropTriggerStatem
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveConfigNodeStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.RemoveDataNodeStatement;
 import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement;
@@ -598,6 +599,10 @@ public abstract class StatementVisitor<R, C> {
     return visitStatement(removeDataNodeStatement, context);
   }
 
+  public R visitRemoveConfigNode(RemoveConfigNodeStatement 
removeConfigNodeStatement, C context) {
+    return visitStatement(removeConfigNodeStatement, context);
+  }
+
   public R visitDeactivateTemplate(
       DeactivateTemplateStatement deactivateTemplateStatement, C context) {
     return visitStatement(deactivateTemplateStatement, context);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/RemoveConfigNodeStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/RemoveConfigNodeStatement.java
new file mode 100644
index 00000000000..8897a298433
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/RemoveConfigNodeStatement.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.statement.metadata;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.auth.AuthorityChecker;
+import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
+import org.apache.iotdb.db.queryengine.plan.statement.IConfigStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.Statement;
+import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import java.util.Collections;
+import java.util.List;
+
+public class RemoveConfigNodeStatement extends Statement implements 
IConfigStatement {
+  final Integer nodeId;
+
+  public RemoveConfigNodeStatement(Integer nodeId) {
+    super();
+    this.nodeId = nodeId;
+  }
+
+  public Integer getNodeId() {
+    return nodeId;
+  }
+
+  @Override
+  public TSStatus checkPermissionBeforeProcess(String userName) {
+    if (AuthorityChecker.SUPER_USER.equals(userName)) {
+      return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+    }
+    return AuthorityChecker.getTSStatus(
+        AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.MAINTAIN.ordinal()),
+        PrivilegeType.MAINTAIN);
+  }
+
+  @Override
+  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+    return visitor.visitRemoveConfigNode(this, context);
+  }
+
+  @Override
+  public QueryType getQueryType() {
+    return QueryType.WRITE;
+  }
+
+  @Override
+  public List<PartialPath> getPaths() {
+    return Collections.emptyList();
+  }
+}

Reply via email to