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 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 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 }