diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionGroupExpandAndShrinkForIoTV1IT.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionGroupExpandAndShrinkForIoTV1IT.java
index c1702ee701d28..c9d0687f7cf18 100644
--- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionGroupExpandAndShrinkForIoTV1IT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionGroupExpandAndShrinkForIoTV1IT.java
@@ -37,11 +37,14 @@
import java.sql.Connection;
import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly;
@@ -51,6 +54,8 @@ public class IoTDBRegionGroupExpandAndShrinkForIoTV1IT
extends IoTDBRegionOperationReliabilityITFramework {
private static final String EXPAND_FORMAT = "extend region %d to %d";
private static final String SHRINK_FORMAT = "remove region %d from %d";
+ private static final String MULTI_EXPAND_FORMAT = "extend region %s to %d";
+ private static final String MULTI_SHRINK_FORMAT = "remove region %s from %d";
private static Logger LOGGER =
LoggerFactory.getLogger(IoTDBRegionGroupExpandAndShrinkForIoTV1IT.class);
@@ -65,7 +70,7 @@ public class IoTDBRegionGroupExpandAndShrinkForIoTV1IT
*
4. Check
*/
@Test
- public void normal1C5DTest() throws Exception {
+ public void singleRegionTest() throws Exception {
EnvFactory.getEnv()
.getConfig()
.getCommonConfig()
@@ -181,4 +186,326 @@ private void regionGroupShrink(
LOGGER.info("Region {} has shrunk from DataNode {}", selectedRegion, targetDataNode);
}
+
+ /**
+ * Test multi-region expand and shrink operations with normal flow: 1. Multi-expand: expand
+ * multiple regions to target DataNode 2. Multi-shrink: shrink multiple regions from target
+ * DataNode
+ */
+ @Test
+ public void multiRegionNormalTest() throws Exception {
+ EnvFactory.getEnv()
+ .getConfig()
+ .getCommonConfig()
+ .setDataRegionConsensusProtocolClass(ConsensusFactory.IOT_CONSENSUS)
+ .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS)
+ .setDataReplicationFactor(1)
+ .setSchemaReplicationFactor(1);
+
+ EnvFactory.getEnv().initClusterEnvironment(1, 5);
+
+ try (final Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection());
+ final Statement statement = makeItCloseQuietly(connection.createStatement());
+ SyncConfigNodeIServiceClient client =
+ (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) {
+ // prepare data
+ statement.execute(INSERTION1);
+ statement.execute(FLUSH_COMMAND);
+
+ // collect necessary information
+ Map> regionMap = getAllRegionMap(statement);
+ Set allDataNodeId = getAllDataNodes(statement);
+
+ // expect one data region, one schema region
+ // plus one system data region, one system schema region
+ Assert.assertEquals(4, regionMap.size());
+
+ // select multiple regions for testing
+ List selectedRegions = new ArrayList<>(regionMap.keySet());
+ selectedRegions = selectedRegions.subList(0, Math.min(3, selectedRegions.size()));
+
+ // find target DataNode that doesn't contain any of the selected regions
+ int targetDataNode =
+ findDataNodeNotContainsAnyRegion(allDataNodeId, regionMap, selectedRegions);
+
+ LOGGER.info("Selected regions for multi-region test: {}", selectedRegions);
+ LOGGER.info("Target DataNode: {}", targetDataNode);
+
+ // multi-expand: expand all selected regions to target DataNode
+ multiRegionGroupExpand(statement, client, selectedRegions, targetDataNode);
+
+ // verify expand result
+ regionMap = getAllRegionMap(statement);
+ for (int regionId : selectedRegions) {
+ Assert.assertTrue(
+ "Region " + regionId + " should contain target DataNode " + targetDataNode,
+ regionMap.get(regionId).contains(targetDataNode));
+ }
+ LOGGER.info("Multi-region expand test passed");
+
+ // multi-shrink: shrink all selected regions from target DataNode
+ multiRegionGroupShrink(statement, client, selectedRegions, targetDataNode);
+
+ // verify shrink result
+ regionMap = getAllRegionMap(statement);
+ for (int regionId : selectedRegions) {
+ Assert.assertFalse(
+ "Region " + regionId + " should not contain target DataNode " + targetDataNode,
+ regionMap.get(regionId).contains(targetDataNode));
+ }
+ LOGGER.info("Multi-region shrink test passed");
+ }
+ }
+
+ /** Test multi-region expand with partial regions already in target DataNode */
+ @Test
+ public void multiRegionExpandPartialExistTest() throws Exception {
+ EnvFactory.getEnv()
+ .getConfig()
+ .getCommonConfig()
+ .setDataRegionConsensusProtocolClass(ConsensusFactory.IOT_CONSENSUS)
+ .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS)
+ .setDataReplicationFactor(1)
+ .setSchemaReplicationFactor(1);
+
+ EnvFactory.getEnv().initClusterEnvironment(1, 5);
+
+ try (final Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection());
+ final Statement statement = makeItCloseQuietly(connection.createStatement());
+ SyncConfigNodeIServiceClient client =
+ (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) {
+ // prepare data
+ statement.execute(INSERTION1);
+ statement.execute(FLUSH_COMMAND);
+
+ Map> regionMap = getAllRegionMap(statement);
+ Set allDataNodeId = getAllDataNodes(statement);
+
+ List allRegions = new ArrayList<>(regionMap.keySet());
+ List selectedRegions = allRegions.subList(0, Math.min(3, allRegions.size()));
+
+ int targetDataNode =
+ findDataNodeNotContainsAnyRegion(allDataNodeId, regionMap, selectedRegions);
+
+ // first expand some regions individually
+ List preExpandRegions =
+ selectedRegions.subList(0, Math.min(2, selectedRegions.size()));
+ for (int regionId : preExpandRegions) {
+ regionGroupExpand(statement, client, regionId, targetDataNode);
+ }
+
+ // now try to expand all regions (including already expanded ones)
+ LOGGER.info(
+ "Testing multi-expand with regions {} to DataNode {}, where {} already exist",
+ selectedRegions,
+ targetDataNode,
+ preExpandRegions);
+
+ multiRegionGroupExpand(statement, client, selectedRegions, targetDataNode);
+
+ // verify all regions are in target DataNode
+ regionMap = getAllRegionMap(statement);
+ for (int regionId : selectedRegions) {
+ Assert.assertTrue(
+ "Region " + regionId + " should contain target DataNode " + targetDataNode,
+ regionMap.get(regionId).contains(targetDataNode));
+ }
+ LOGGER.info("Multi-region expand partial exist test passed");
+ }
+ }
+
+ /** Test multi-region shrink with partial regions not in target DataNode */
+ @Test
+ public void multiRegionShrinkPartialNotExistTest() throws Exception {
+ EnvFactory.getEnv()
+ .getConfig()
+ .getCommonConfig()
+ .setDataRegionConsensusProtocolClass(ConsensusFactory.IOT_CONSENSUS)
+ .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS)
+ .setDataReplicationFactor(1)
+ .setSchemaReplicationFactor(1);
+
+ EnvFactory.getEnv().initClusterEnvironment(1, 5);
+
+ try (final Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection());
+ final Statement statement = makeItCloseQuietly(connection.createStatement());
+ SyncConfigNodeIServiceClient client =
+ (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) {
+ // prepare data
+ statement.execute(INSERTION1);
+ statement.execute(FLUSH_COMMAND);
+
+ Map> regionMap = getAllRegionMap(statement);
+ Set allDataNodeId = getAllDataNodes(statement);
+
+ List allRegions = new ArrayList<>(regionMap.keySet());
+ List selectedRegions = allRegions.subList(0, Math.min(3, allRegions.size()));
+
+ int targetDataNode =
+ findDataNodeNotContainsAnyRegion(allDataNodeId, regionMap, selectedRegions);
+
+ // first expand all regions to target DataNode
+ multiRegionGroupExpand(statement, client, selectedRegions, targetDataNode);
+
+ // then shrink some regions individually
+ List preShrinkRegions =
+ selectedRegions.subList(0, Math.min(2, selectedRegions.size()));
+ for (int regionId : preShrinkRegions) {
+ regionGroupShrink(statement, client, regionId, targetDataNode);
+ }
+
+ // now try to shrink all regions (including already shrunk ones)
+ LOGGER.info(
+ "Testing multi-shrink with regions {} from DataNode {}, where {} already removed",
+ selectedRegions,
+ targetDataNode,
+ preShrinkRegions);
+
+ multiRegionGroupShrink(statement, client, selectedRegions, targetDataNode);
+
+ // verify all regions are not in target DataNode
+ regionMap = getAllRegionMap(statement);
+ for (int regionId : selectedRegions) {
+ Assert.assertFalse(
+ "Region " + regionId + " should not contain target DataNode " + targetDataNode,
+ regionMap.get(regionId).contains(targetDataNode));
+ }
+ LOGGER.info("Multi-region shrink partial not exist test passed");
+ }
+ }
+
+ private void multiRegionGroupExpand(
+ Statement statement,
+ SyncConfigNodeIServiceClient client,
+ List regionIds,
+ int targetDataNode)
+ throws Exception {
+ String command = buildMultiRegionCommand(MULTI_EXPAND_FORMAT, regionIds, targetDataNode);
+
+ Predicate expandPredicate =
+ tShowRegionResp -> {
+ Map> newRegionMap =
+ getRunningRegionMap(tShowRegionResp.getRegionInfoList());
+ return regionIds.stream()
+ .allMatch(
+ regionId -> {
+ Set dataNodes = newRegionMap.get(regionId);
+ return dataNodes != null && dataNodes.contains(targetDataNode);
+ });
+ };
+
+ executeMultiRegionOperation(
+ statement,
+ client,
+ command,
+ regionIds,
+ expandPredicate,
+ Optional.of(targetDataNode),
+ Optional.empty(),
+ "expand");
+ }
+
+ private void multiRegionGroupShrink(
+ Statement statement,
+ SyncConfigNodeIServiceClient client,
+ List regionIds,
+ int targetDataNode)
+ throws Exception {
+ String command = buildMultiRegionCommand(MULTI_SHRINK_FORMAT, regionIds, targetDataNode);
+
+ Predicate shrinkPredicate =
+ tShowRegionResp -> {
+ Map> newRegionMap =
+ getRegionMap(tShowRegionResp.getRegionInfoList());
+ return regionIds.stream()
+ .allMatch(
+ regionId -> {
+ Set dataNodes = newRegionMap.get(regionId);
+ return dataNodes == null || !dataNodes.contains(targetDataNode);
+ });
+ };
+
+ executeMultiRegionOperation(
+ statement,
+ client,
+ command,
+ regionIds,
+ shrinkPredicate,
+ Optional.empty(),
+ Optional.of(targetDataNode),
+ "shrink");
+ }
+
+ private String buildMultiRegionCommand(
+ String format, List regionIds, int targetDataNode) {
+ String regionIdStr = regionIds.stream().map(String::valueOf).collect(Collectors.joining(","));
+ return String.format(format, regionIdStr, targetDataNode);
+ }
+
+ private void executeMultiRegionOperation(
+ Statement statement,
+ SyncConfigNodeIServiceClient client,
+ String command,
+ List regionIds,
+ Predicate predicate,
+ Optional expectedDataNode,
+ Optional notExpectedDataNode,
+ String operationType) {
+
+ LOGGER.info("Executing multi-region {} command: {}", operationType, command);
+
+ Awaitility.await()
+ .atMost(30, TimeUnit.SECONDS)
+ .pollInterval(2, TimeUnit.SECONDS)
+ .until(
+ () -> {
+ try {
+ statement.execute(command);
+ return true;
+ } catch (Exception e) {
+ String errorMessage = e.getMessage();
+ // If error message contains both "successfully submitted" and "failed to submit",
+ // consider it as partial success and continue
+ if (errorMessage != null
+ && errorMessage.contains("successfully submitted")
+ && errorMessage.contains("failed to submit")) {
+ LOGGER.warn(
+ "Multi-region {} partially succeeded: {}", operationType, errorMessage);
+ return true;
+ }
+ LOGGER.warn(
+ "Multi-region {} command execution failed, retrying: {}",
+ operationType,
+ errorMessage);
+ return false;
+ }
+ });
+
+ // Use the first region for awaitUntilSuccess (framework limitation)
+ awaitUntilSuccess(client, regionIds.get(0), predicate, expectedDataNode, notExpectedDataNode);
+
+ String targetDescription =
+ expectedDataNode.isPresent()
+ ? "to DataNode " + expectedDataNode.get()
+ : "from DataNode " + notExpectedDataNode.get();
+ LOGGER.info(
+ "Regions {} have {} {}",
+ regionIds,
+ operationType.equals("expand") ? "expanded" : "shrunk",
+ targetDescription);
+ }
+
+ private int findDataNodeNotContainsAnyRegion(
+ Set allDataNodeId, Map> regionMap, List regionIds) {
+ return allDataNodeId.stream()
+ .filter(
+ dataNodeId ->
+ regionIds.stream()
+ .noneMatch(regionId -> regionMap.get(regionId).contains(dataNodeId)))
+ .findFirst()
+ .orElseThrow(
+ () ->
+ new RuntimeException(
+ "Cannot find DataNode that doesn't contain any of the regions"));
+ }
}
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 789fac304a6ce..475a40dd0cab7 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
@@ -541,11 +541,11 @@ reconstructRegion
;
extendRegion
- : EXTEND REGION regionId=INTEGER_LITERAL TO targetDataNodeId=INTEGER_LITERAL
+ : EXTEND REGION regionIds+=INTEGER_LITERAL (COMMA regionIds+=INTEGER_LITERAL)* TO targetDataNodeId=INTEGER_LITERAL
;
removeRegion
- : REMOVE REGION regionId=INTEGER_LITERAL FROM targetDataNodeId=INTEGER_LITERAL
+ : REMOVE REGION regionIds+=INTEGER_LITERAL (COMMA regionIds+=INTEGER_LITERAL)* FROM targetDataNodeId=INTEGER_LITERAL
;
verifyConnection
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 20d706a12527e..3071830be60be 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
@@ -2489,7 +2489,7 @@ public TSStatus reconstructRegion(TReconstructRegionReq req) {
public TSStatus extendRegion(TExtendRegionReq req) {
TSStatus status = confirmLeader();
return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()
- ? procedureManager.extendRegion(req)
+ ? procedureManager.extendRegions(req)
: status;
}
@@ -2497,7 +2497,7 @@ public TSStatus extendRegion(TExtendRegionReq req) {
public TSStatus removeRegion(TRemoveRegionReq req) {
TSStatus status = confirmLeader();
return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()
- ? procedureManager.removeRegion(req)
+ ? procedureManager.removeRegions(req)
: 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 9a5feb0b407d1..3dcb01de2733b 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
@@ -176,6 +176,7 @@
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -824,7 +825,7 @@ private TSStatus checkExtendRegion(
failMessage =
String.format(
"Target DataNode %s already contains region %s",
- targetDataNode.getDataNodeId(), req.getRegionId());
+ targetDataNode.getDataNodeId(), regionId);
}
if (failMessage != null) {
@@ -1125,14 +1126,60 @@ public TSStatus reconstructRegion(TReconstructRegionReq req) {
return RpcUtils.SUCCESS_STATUS;
}
- public TSStatus extendRegion(TExtendRegionReq req) {
+ public TSStatus extendRegions(TExtendRegionReq req) {
+ return processExtendOrRemoveRegions(
+ req.getRegionId(), req, this::extendOneRegion, TSStatusCode.EXTEND_REGION_ERROR);
+ }
+
+ public TSStatus removeRegions(TRemoveRegionReq req) {
+ return processExtendOrRemoveRegions(
+ req.getRegionId(), req, this::removeOneRegion, TSStatusCode.REMOVE_REGION_PEER_ERROR);
+ }
+
+ private TSStatus processExtendOrRemoveRegions(
+ Iterable regionIds,
+ R req,
+ BiFunction regionAction,
+ TSStatusCode errorCode) {
+ TSStatus resp = new TSStatus();
+ StringBuilder messageBuilder = new StringBuilder();
+
+ int total = 0, success = 0;
+ for (int regionId : regionIds) {
+ total++;
+ TSStatus subStatus = regionAction.apply(regionId, req);
+ if (subStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ messageBuilder.append("region ").append(regionId).append(": Successfully submitted\n");
+ success++;
+ } else {
+ messageBuilder
+ .append("region ")
+ .append(regionId)
+ .append(": ")
+ .append(subStatus.getMessage())
+ .append('\n');
+ }
+ resp.addToSubStatus(subStatus);
+ }
+
+ messageBuilder.insert(
+ 0,
+ String.format(
+ "Total regions: %d, successfully submitted: %d, failed to submit: %d\n",
+ total, success, total - success));
+
+ resp.setCode(
+ total == success ? TSStatusCode.SUCCESS_STATUS.getStatusCode() : errorCode.getStatusCode());
+ resp.setMessage(messageBuilder.toString());
+ return resp;
+ }
+
+ private TSStatus extendOneRegion(int theRegionId, TExtendRegionReq req) {
try (AutoCloseableLock ignoredLock =
AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) {
TConsensusGroupId regionId;
Optional optional =
- configManager
- .getPartitionManager()
- .generateTConsensusGroupIdByRegionId(req.getRegionId());
+ configManager.getPartitionManager().generateTConsensusGroupIdByRegionId(theRegionId);
if (optional.isPresent()) {
regionId = optional.get();
} else {
@@ -1171,14 +1218,12 @@ public TSStatus extendRegion(TExtendRegionReq req) {
}
}
- public TSStatus removeRegion(TRemoveRegionReq req) {
+ private TSStatus removeOneRegion(int theRegionId, TRemoveRegionReq req) {
try (AutoCloseableLock ignoredLock =
AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) {
TConsensusGroupId regionId;
Optional optional =
- configManager
- .getPartitionManager()
- .generateTConsensusGroupIdByRegionId(req.getRegionId());
+ configManager.getPartitionManager().generateTConsensusGroupIdByRegionId(theRegionId);
if (optional.isPresent()) {
regionId = optional.get();
} else {
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 d5dc521292e26..9e57532ad2611 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
@@ -3213,7 +3213,7 @@ public SettableFuture extendRegion(ExtendRegionTask extendRegi
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
final TExtendRegionReq req =
new TExtendRegionReq(
- extendRegionTask.getStatement().getRegionId(),
+ extendRegionTask.getStatement().getRegionIds(),
extendRegionTask.getStatement().getDataNodeId(),
extendRegionTask.getModel());
final TSStatus status = configNodeClient.extendRegion(req);
@@ -3236,7 +3236,7 @@ public SettableFuture removeRegion(RemoveRegionTask removeRegi
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) {
final TRemoveRegionReq req =
new TRemoveRegionReq(
- removeRegionTask.getStatement().getRegionId(),
+ removeRegionTask.getStatement().getRegionIds(),
removeRegionTask.getStatement().getDataNodeId(),
removeRegionTask.getModel());
final TSStatus status = configNodeClient.removeRegion(req);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ExtendRegionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ExtendRegionTask.java
index 1ffce01092760..8635c085ee1a1 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ExtendRegionTask.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ExtendRegionTask.java
@@ -40,7 +40,7 @@ public ExtendRegionTask(ExtendRegionStatement statement) {
public ExtendRegionTask(ExtendRegion extendRegion) {
this.statement =
- new ExtendRegionStatement(extendRegion.getRegionId(), extendRegion.getDataNodeId());
+ new ExtendRegionStatement(extendRegion.getRegionIds(), extendRegion.getDataNodeId());
this.model = Model.TABLE;
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/RemoveRegionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/RemoveRegionTask.java
index 86d4bafc9db8c..e1d32bff98626 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/RemoveRegionTask.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/RemoveRegionTask.java
@@ -40,7 +40,7 @@ public RemoveRegionTask(RemoveRegionStatement statement) {
public RemoveRegionTask(RemoveRegion removeRegion) {
this.statement =
- new RemoveRegionStatement(removeRegion.getRegionId(), removeRegion.getDataNodeId());
+ new RemoveRegionStatement(removeRegion.getRegionIds(), removeRegion.getDataNodeId());
this.model = Model.TABLE;
}
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 706d14f052cd2..aa8a8621784d6 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
@@ -289,6 +289,7 @@
import java.util.stream.Collectors;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static java.util.stream.Collectors.toList;
import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_RESULT_NODES;
import static org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.FIELD;
import static org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory.TAG;
@@ -4277,14 +4278,16 @@ public Statement visitReconstructRegion(IoTDBSqlParser.ReconstructRegionContext
@Override
public Statement visitExtendRegion(IoTDBSqlParser.ExtendRegionContext ctx) {
- return new ExtendRegionStatement(
- Integer.parseInt(ctx.regionId.getText()), Integer.parseInt(ctx.targetDataNodeId.getText()));
+ List regionIds =
+ ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
+ return new ExtendRegionStatement(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
}
@Override
public Statement visitRemoveRegion(IoTDBSqlParser.RemoveRegionContext ctx) {
- return new RemoveRegionStatement(
- Integer.parseInt(ctx.regionId.getText()), Integer.parseInt(ctx.targetDataNodeId.getText()));
+ List regionIds =
+ ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
+ return new RemoveRegionStatement(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
}
@Override
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ExtendRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ExtendRegion.java
index 687777c85588e..056be45d151d9 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ExtendRegion.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ExtendRegion.java
@@ -26,12 +26,12 @@
public class ExtendRegion extends Statement {
- private final int regionId;
+ private final List regionIds;
private final int dataNodeId;
- public ExtendRegion(int regionId, int dataNodeId) {
+ public ExtendRegion(List regionIds, int dataNodeId) {
super(null);
- this.regionId = regionId;
+ this.regionIds = regionIds;
this.dataNodeId = dataNodeId;
}
@@ -42,7 +42,7 @@ public List extends Node> getChildren() {
@Override
public int hashCode() {
- return Objects.hash(ExtendRegion.class, regionId, dataNodeId);
+ return Objects.hash(ExtendRegion.class, regionIds, dataNodeId);
}
@Override
@@ -54,12 +54,12 @@ public boolean equals(Object obj) {
return false;
}
ExtendRegion another = (ExtendRegion) obj;
- return regionId == another.regionId && dataNodeId == another.dataNodeId;
+ return regionIds.equals(another.regionIds) && dataNodeId == another.dataNodeId;
}
@Override
public String toString() {
- return String.format("extend region %d to datanode %d", regionId, dataNodeId);
+ return String.format("extend region %s to datanode %d", regionIds, dataNodeId);
}
@Override
@@ -67,8 +67,8 @@ public R accept(AstVisitor visitor, C context) {
return visitor.visitExtendRegion(this, context);
}
- public int getRegionId() {
- return regionId;
+ public List getRegionIds() {
+ return regionIds;
}
public int getDataNodeId() {
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RemoveRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RemoveRegion.java
index 8c14433167a86..9dc1dad708364 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RemoveRegion.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RemoveRegion.java
@@ -26,12 +26,12 @@
public class RemoveRegion extends Statement {
- private final int regionId;
+ private final List regionIds;
private final int dataNodeId;
- public RemoveRegion(int regionId, int dataNodeId) {
+ public RemoveRegion(List regionId, int dataNodeId) {
super(null);
- this.regionId = regionId;
+ this.regionIds = regionId;
this.dataNodeId = dataNodeId;
}
@@ -42,7 +42,7 @@ public List extends Node> getChildren() {
@Override
public int hashCode() {
- return Objects.hash(RemoveRegion.class, regionId, dataNodeId);
+ return Objects.hash(RemoveRegion.class, regionIds, dataNodeId);
}
@Override
@@ -54,12 +54,12 @@ public boolean equals(Object obj) {
return false;
}
RemoveRegion another = (RemoveRegion) obj;
- return regionId == another.regionId && dataNodeId == another.dataNodeId;
+ return regionIds.equals(another.regionIds) && dataNodeId == another.dataNodeId;
}
@Override
public String toString() {
- return String.format("remove region %d from %d", regionId, dataNodeId);
+ return String.format("remove region %s from %d", regionIds, dataNodeId);
}
@Override
@@ -67,8 +67,8 @@ public R accept(AstVisitor visitor, C context) {
return visitor.visitRemoveRegion(this, context);
}
- public int getRegionId() {
- return regionId;
+ public List getRegionIds() {
+ return regionIds;
}
public int getDataNodeId() {
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index b445f23bff9ce..a69eead9a40ad 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -1438,14 +1438,16 @@ public Node visitReconstructRegionStatement(
@Override
public Node visitExtendRegionStatement(RelationalSqlParser.ExtendRegionStatementContext ctx) {
- return new ExtendRegion(
- Integer.parseInt(ctx.regionId.getText()), Integer.parseInt(ctx.targetDataNodeId.getText()));
+ List regionIds =
+ ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
+ return new ExtendRegion(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
}
@Override
public Node visitRemoveRegionStatement(RelationalSqlParser.RemoveRegionStatementContext ctx) {
- return new RemoveRegion(
- Integer.parseInt(ctx.regionId.getText()), Integer.parseInt(ctx.targetDataNodeId.getText()));
+ List regionIds =
+ ctx.regionIds.stream().map(token -> Integer.parseInt(token.getText())).collect(toList());
+ return new RemoveRegion(regionIds, Integer.parseInt(ctx.targetDataNodeId.getText()));
}
@Override
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java
index 0048a789f9576..591c62c4b6bfd 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java
@@ -32,17 +32,17 @@
public class ExtendRegionStatement extends Statement implements IConfigStatement {
- private final int regionId;
+ private final List regionIds;
private final int dataNodeId;
- public ExtendRegionStatement(int regionId, int dataNodeId) {
+ public ExtendRegionStatement(List regionIds, int dataNodeId) {
super();
- this.regionId = regionId;
+ this.regionIds = regionIds;
this.dataNodeId = dataNodeId;
}
- public int getRegionId() {
- return regionId;
+ public List getRegionIds() {
+ return regionIds;
}
public int getDataNodeId() {
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/RemoveRegionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/RemoveRegionStatement.java
index aa185ad627ef3..f4d3b94c68266 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/RemoveRegionStatement.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/RemoveRegionStatement.java
@@ -32,17 +32,17 @@
public class RemoveRegionStatement extends Statement implements IConfigStatement {
- private final int regionId;
+ private final List regionIds;
private final int dataNodeId;
- public RemoveRegionStatement(int regionId, int dataNodeId) {
+ public RemoveRegionStatement(List regionIds, int dataNodeId) {
super();
- this.regionId = regionId;
+ this.regionIds = regionIds;
this.dataNodeId = dataNodeId;
}
- public int getRegionId() {
- return regionId;
+ public List getRegionIds() {
+ return regionIds;
}
public int getDataNodeId() {
diff --git a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index 8aa8ac380d261..1d5d8dcecadd5 100644
--- a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -573,15 +573,15 @@ migrateRegionStatement
;
reconstructRegionStatement
- : RECONSTRUCT REGION regionIds+=INTEGER_VALUE (COMMA regionIds+=INTEGER_VALUE)* ON targetDataNodeId=INTEGER_VALUE
+ : RECONSTRUCT REGION regionIds+=INTEGER_VALUE (',' regionIds+=INTEGER_VALUE)* ON targetDataNodeId=INTEGER_VALUE
;
extendRegionStatement
- : EXTEND REGION regionId=INTEGER_VALUE TO targetDataNodeId=INTEGER_VALUE
+ : EXTEND REGION regionIds+=INTEGER_VALUE (',' regionIds+=INTEGER_VALUE)* TO targetDataNodeId=INTEGER_VALUE
;
removeRegionStatement
- : REMOVE REGION regionId=INTEGER_VALUE FROM targetDataNodeId=INTEGER_VALUE
+ : REMOVE REGION regionIds+=INTEGER_VALUE (',' regionIds+=INTEGER_VALUE)* FROM targetDataNodeId=INTEGER_VALUE
;
removeDataNodeStatement
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index 2a5682926dfc9..99e11d8116d0d 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -322,13 +322,13 @@ struct TReconstructRegionReq {
}
struct TExtendRegionReq {
- 1: required i32 regionId
+ 1: required list regionId
2: required i32 dataNodeId
3: required common.Model model
}
struct TRemoveRegionReq {
- 1: required i32 regionId
+ 1: required list regionId
2: required i32 dataNodeId
3: required common.Model model
}