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();
+ }
+}