diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvFactory.java b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvFactory.java index ce8046708a87..a71e4e7a3aee 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvFactory.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvFactory.java @@ -20,6 +20,7 @@ package org.apache.iotdb.it.env; import org.apache.iotdb.it.env.cluster.env.AIEnv; +import org.apache.iotdb.it.env.cluster.env.AbstractEnv; import org.apache.iotdb.it.env.cluster.env.Cluster1Env; import org.apache.iotdb.it.env.cluster.env.SimpleEnv; import org.apache.iotdb.it.env.remote.env.RemoteServerEnv; @@ -75,4 +76,8 @@ public static BaseEnv getEnv() { } return env; } + + public static AbstractEnv getAbstractEnv() { + return (AbstractEnv) getEnv(); + } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java index f675f96606ab..ccf226bafd2c 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java @@ -330,6 +330,10 @@ private Map countNodeStatus(final Map nodeStat return result; } + public void checkNodeInStatus(int nodeId, NodeStatus expectation) { + checkClusterStatus(nodeStatusMap -> expectation.getStatus().equals(nodeStatusMap.get(nodeId))); + } + public void checkClusterStatusWithoutUnknown() { checkClusterStatus( nodeStatusMap -> nodeStatusMap.values().stream().noneMatch("Unknown"::equals)); diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AINodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AINodeWrapper.java index c503dfc00e7d..8da2437aed68 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AINodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AINodeWrapper.java @@ -90,6 +90,11 @@ public String getLogDirPath() { + getTimeForLogDirectory(startTime); } + @Override + String getNodeType() { + return "ainode"; + } + @Override public void start() { try { diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java index c42db717a935..3b6d84069819 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java @@ -630,6 +630,18 @@ public String getNodePath() { return System.getProperty(USER_DIR) + File.separator + TARGET + File.separator + getId(); } + public String getDataPath() { + return getNodePath() + + File.separator + + IoTDBConstant.DATA_FOLDER_NAME + + File.separator + + getNodeType() + + File.separator + + IoTDBConstant.DATA_FOLDER_NAME; + } + + abstract String getNodeType(); + public void dumpJVMSnapshot(String testCaseName) { JMXServiceURL url; try { diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java index 2b3211fe8681..aafb3641fc1d 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java @@ -139,6 +139,11 @@ protected void addStartCmdParams(final List params) { "-s")); } + @Override + String getNodeType() { + return "confignode"; + } + @Override protected void reloadMutableFields() { mutableCommonProperties.setProperty(CONFIG_NODE_CONSENSUS_PROTOCOL_CLASS, SIMPLE_CONSENSUS); diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java index 127f9b331857..3df21cb42a69 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java @@ -175,6 +175,11 @@ protected void addStartCmdParams(final List params) { "-s")); } + @Override + String getNodeType() { + return "datanode"; + } + @Override protected void reloadMutableFields() { mutableCommonProperties.setProperty(CONFIG_NODE_CONSENSUS_PROTOCOL_CLASS, SIMPLE_CONSENSUS); diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV1.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV1.java index 334e91352ec8..7899d570bc4e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV1.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV1.java @@ -26,7 +26,7 @@ import org.junit.Before; public class IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV1 - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV2.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV2.java index 54635c00a5c7..e48178600739 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV2.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV2.java @@ -22,7 +22,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; public class IoTDBRegionMigrateDataNodeCrashITFrameworkForIoTV2 - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @SafeVarargs public final > void success(T... dataNodeKillPoints) throws Exception { diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateReliabilityITFramework.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionOperationReliabilityITFramework.java similarity index 82% rename from integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateReliabilityITFramework.java rename to integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionOperationReliabilityITFramework.java index d82022587a58..92cf2b877079 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionMigrateReliabilityITFramework.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/IoTDBRegionOperationReliabilityITFramework.java @@ -21,6 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType; import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; +import org.apache.iotdb.commons.cluster.RegionStatus; import org.apache.iotdb.commons.concurrent.IoTDBThreadPoolFactory; import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant; @@ -31,15 +32,19 @@ import org.apache.iotdb.confignode.rpc.thrift.TShowRegionResp; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.consensus.iot.IoTConsensusServerImpl; +import org.apache.iotdb.isession.SessionDataSet; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.env.cluster.env.AbstractEnv; import org.apache.iotdb.it.env.cluster.node.AbstractNodeWrapper; import org.apache.iotdb.it.env.cluster.node.ConfigNodeWrapper; import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper; -import org.apache.iotdb.itbase.exception.InconsistentDataException; import org.apache.iotdb.metrics.utils.SystemType; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.Session; import org.apache.thrift.TException; +import org.apache.tsfile.read.common.Field; import org.awaitility.Awaitility; import org.awaitility.core.ConditionTimeoutException; import org.junit.After; @@ -52,9 +57,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -69,22 +71,26 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap.KeySetView; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; -public class IoTDBRegionMigrateReliabilityITFramework { +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; + +public class IoTDBRegionOperationReliabilityITFramework { private static final Logger LOGGER = - LoggerFactory.getLogger(IoTDBRegionMigrateReliabilityITFramework.class); - private static final String INSERTION1 = + LoggerFactory.getLogger(IoTDBRegionOperationReliabilityITFramework.class); + public static final String INSERTION1 = "INSERT INTO root.sg.d1(timestamp,speed,temperature) values(100, 1, 2)"; private static final String INSERTION2 = "INSERT INTO root.sg.d1(timestamp,speed,temperature) values(101, 3, 4)"; - private static final String FLUSH_COMMAND = "flush"; + public static final String FLUSH_COMMAND = "flush on cluster"; private static final String SHOW_REGIONS = "show regions"; private static final String SHOW_DATANODES = "show datanodes"; private static final String COUNT_TIMESERIES = "select count(*) from root.sg.**"; @@ -208,35 +214,26 @@ public void generalTestWithAllOptions( EnvFactory.getEnv().registerDataNodeKillPoints(new ArrayList<>(dataNodeKeywords)); EnvFactory.getEnv().initClusterEnvironment(configNodeNum, dataNodeNum); - try (final Connection connection = closeQuietly(EnvFactory.getEnv().getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); + 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); - ResultSet result = statement.executeQuery(SHOW_REGIONS); - Map> regionMap = getRegionMap(result); - - result = statement.executeQuery(SHOW_DATANODES); - Set allDataNodeId = new HashSet<>(); - while (result.next()) { - allDataNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID)); - } + // collect necessary information + Map> regionMap = getDataRegionMap(statement); + Set allDataNodeId = getAllDataNodes(statement); + // select region migration related DataNodes final int selectedRegion = selectRegion(regionMap); final int originalDataNode = selectOriginalDataNode(regionMap, selectedRegion); - final int destDataNode = selectDestDataNode(allDataNodeId, regionMap, selectedRegion); - + final int destDataNode = + selectDataNodeNotContainsRegion(allDataNodeId, regionMap, selectedRegion); checkRegionFileExist(originalDataNode); checkPeersExist(regionMap.get(selectedRegion), originalDataNode, selectedRegion); - try { - awaitUntilFlush(statement, originalDataNode); - } catch (ConditionTimeoutException e) { - LOGGER.error("Flush timeout:", e); - Assert.fail(); - } - // set kill points if (killNode == KillNode.ORIGINAL_DATANODE) { setDataNodeKillPoints( @@ -270,8 +267,19 @@ public void generalTestWithAllOptions( statement.execute(buildRegionMigrateCommand(selectedRegion, originalDataNode, destDataNode)); boolean success = false; + Predicate migrateRegionPredicate = + tShowRegionResp -> { + Map> newRegionMap = + getRegionMap(tShowRegionResp.getRegionInfoList()); + Set dataNodes = newRegionMap.get(selectedRegion); + return !dataNodes.contains(originalDataNode) && dataNodes.contains(destDataNode); + }; try { - awaitUntilSuccess(client, selectedRegion, originalDataNode, destDataNode); + awaitUntilSuccess( + client, + migrateRegionPredicate, + Optional.of(destDataNode), + Optional.of(originalDataNode)); success = true; } catch (ConditionTimeoutException e) { if (expectMigrateSuccess) { @@ -301,9 +309,16 @@ public void generalTestWithAllOptions( } LOGGER.info("test pass"); - } catch (InconsistentDataException ignore) { + } + } + protected Set getAllDataNodes(Statement statement) throws Exception { + ResultSet result = statement.executeQuery(SHOW_DATANODES); + Set allDataNodeId = new HashSet<>(); + while (result.next()) { + allDataNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID)); } + return allDataNodeId; } private void setConfigNodeKillPoints( @@ -420,8 +435,8 @@ private static String buildRegionMigrateCommand(int who, int from, int to) { return result; } - public static Map> getRegionMap(ResultSet showRegionsResult) - throws SQLException { + public static Map> getDataRegionMap(Statement statement) throws Exception { + ResultSet showRegionsResult = statement.executeQuery(SHOW_REGIONS); Map> regionMap = new HashMap<>(); while (showRegionsResult.next()) { if (String.valueOf(TConsensusGroupType.DataRegion) @@ -434,7 +449,18 @@ public static Map> getRegionMap(ResultSet showRegionsResul return regionMap; } - private static Map> getRegionMap(List regionInfoList) { + public static Map> getAllRegionMap(Statement statement) throws Exception { + ResultSet showRegionsResult = statement.executeQuery(SHOW_REGIONS); + Map> regionMap = new HashMap<>(); + while (showRegionsResult.next()) { + int regionId = showRegionsResult.getInt(ColumnHeaderConstant.REGION_ID); + int dataNodeId = showRegionsResult.getInt(ColumnHeaderConstant.DATA_NODE_ID); + regionMap.computeIfAbsent(regionId, id -> new HashSet<>()).add(dataNodeId); + } + return regionMap; + } + + protected static Map> getRegionMap(List regionInfoList) { Map> regionMap = new HashMap<>(); regionInfoList.forEach( regionInfo -> { @@ -446,7 +472,22 @@ private static Map> getRegionMap(List regionI return regionMap; } - private static int selectRegion(Map> regionMap) { + protected static Map> getRunningRegionMap( + List regionInfoList) { + Map> regionMap = new HashMap<>(); + regionInfoList.stream() + .filter(regionInfo -> RegionStatus.Running.getStatus().equals(regionInfo.getStatus())) + .forEach( + regionInfo -> { + int regionId = regionInfo.getConsensusGroupId().getId(); + regionMap + .computeIfAbsent(regionId, regionId1 -> new HashSet<>()) + .add(regionInfo.getDataNodeId()); + }); + return regionMap; + } + + protected static int selectRegion(Map> regionMap) { return regionMap.keySet().stream().findAny().orElseThrow(() -> new RuntimeException("gg")); } @@ -457,7 +498,7 @@ private static int selectOriginalDataNode( .orElseThrow(() -> new RuntimeException("cannot find original DataNode")); } - private static int selectDestDataNode( + protected static int selectDataNodeNotContainsRegion( Set dataNodeSet, Map> regionMap, int selectedRegion) { return dataNodeSet.stream() .filter(dataNodeId -> !regionMap.get(selectedRegion).contains(dataNodeId)) @@ -465,7 +506,16 @@ private static int selectDestDataNode( .orElseThrow(() -> new RuntimeException("cannot find dest DataNode")); } - private static void awaitUntilFlush(Statement statement, int originalDataNode) { + protected static int selectDataNodeContainsRegion( + Set dataNodeSet, Map> regionMap, int selectedRegion) { + return dataNodeSet.stream() + .filter(dataNodeId -> regionMap.get(selectedRegion).contains(dataNodeId)) + .findAny() + .orElseThrow(() -> new RuntimeException("cannot find dest DataNode")); + } + + // I believe this function is not necessary, just keep it here in case it's necessary + private static void awaitUntilFlush(Statement statement, int originalDataNode) throws Exception { long startTime = System.currentTimeMillis(); File sequence = new File(buildDataPath(originalDataNode, true)); File unsequence = new File(buildDataPath(originalDataNode, false)); @@ -488,11 +538,11 @@ private static void awaitUntilFlush(Statement statement, int originalDataNode) { LOGGER.info("Flush cost time: {}ms", System.currentTimeMillis() - startTime); } - private static void awaitUntilSuccess( + protected static void awaitUntilSuccess( SyncConfigNodeIServiceClient client, - int selectedRegion, - int originalDataNode, - int destDataNode) { + Predicate predicate, + Optional dataNodeExpectInRegionGroup, + Optional dataNodeExpectNotInRegionGroup) { AtomicReference> lastTimeDataNodes = new AtomicReference<>(); AtomicReference lastException = new AtomicReference<>(); AtomicReference clientRef = new AtomicReference<>(client); @@ -504,10 +554,7 @@ private static void awaitUntilSuccess( () -> { try { TShowRegionResp resp = clientRef.get().showRegion(new TShowRegionReq()); - Map> newRegionMap = getRegionMap(resp.getRegionInfoList()); - Set dataNodes = newRegionMap.get(selectedRegion); - lastTimeDataNodes.set(dataNodes); - return !dataNodes.contains(originalDataNode) && dataNodes.contains(destDataNode); + return predicate.test(resp); } catch (TException e) { clientRef.set( (SyncConfigNodeIServiceClient) @@ -528,8 +575,8 @@ private static void awaitUntilSuccess( throw e; } String actualSetStr = lastTimeDataNodes.get().toString(); - lastTimeDataNodes.get().remove(originalDataNode); - lastTimeDataNodes.get().add(destDataNode); + dataNodeExpectNotInRegionGroup.ifPresent(x -> lastTimeDataNodes.get().remove(x)); + dataNodeExpectInRegionGroup.ifPresent(x -> lastTimeDataNodes.get().add(x)); String expectSetStr = lastTimeDataNodes.toString(); LOGGER.error("DataNode Set {} is unexpected, expect {}", actualSetStr, expectSetStr); if (lastException.get() == null) { @@ -703,26 +750,21 @@ protected static > KeySetView buildSet(T... k return result; } - public static T closeQuietly(T t) { - InvocationHandler handler = - (proxy, method, args) -> { - try { - if (method.getName().equals("close")) { - try { - method.invoke(t, args); - } catch (Throwable e) { - LOGGER.warn("Exception happens during close(): ", e); - } - return null; - } else { - return method.invoke(t, args); - } - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - }; - return (T) - Proxy.newProxyInstance( - t.getClass().getClassLoader(), t.getClass().getInterfaces(), handler); + protected static Map getRegionStatusWithoutRunning(Session session) + throws IoTDBConnectionException, StatementExecutionException { + SessionDataSet dataSet = session.executeQueryStatement("show regions"); + final int regionIdIndex = dataSet.getColumnNames().indexOf("RegionId"); + final int regionStatusIndex = dataSet.getColumnNames().indexOf("Status"); + dataSet.setFetchSize(1024); + Map result = new TreeMap<>(); + while (dataSet.hasNext()) { + List fields = dataSet.next().getFields(); + final int regionId = fields.get(regionIdIndex).getIntV(); + final String regionStatus = fields.get(regionStatusIndex).toString(); + if (!"Running".equals(regionStatus)) { + result.putIfAbsent(regionId, regionStatus); + } + } + return result; } } 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 new file mode 100644 index 000000000000..7897fded0747 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionGroupExpandAndShrinkForIoTV1IT.java @@ -0,0 +1,157 @@ +/* + * 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.regionmigration.pass.commit; + +import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; +import org.apache.iotdb.confignode.rpc.thrift.TShowRegionResp; +import org.apache.iotdb.consensus.ConsensusFactory; +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.ClusterIT; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.Statement; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; + +@Category({ClusterIT.class}) +@RunWith(IoTDBTestRunner.class) +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 Logger LOGGER = + LoggerFactory.getLogger(IoTDBRegionGroupExpandAndShrinkForIoTV1IT.class); + + /** + * 1. Expand: {a} -> {a,b} -> ... -> {a,b,c,d,e} + * + *

2. Check + * + *

3. Shrink: {a,b,c,d,e} -> {a,c,d,e} -> ... -> {d} + * + *

4. Check + */ + @Test + public void normal1C5DTest() 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 + Assert.assertEquals(2, regionMap.size()); + + // expand + for (int selectedRegion : regionMap.keySet()) { + for (int i = 0; i < 4; i++) { + int targetDataNode = + selectDataNodeNotContainsRegion(allDataNodeId, regionMap, selectedRegion); + regionGroupExpand(statement, client, selectedRegion, targetDataNode); + // update regionMap every time + regionMap = getAllRegionMap(statement); + } + } + + // shrink + for (int selectedRegion : regionMap.keySet()) { + for (int i = 0; i < 4; i++) { + int targetDataNode = + selectDataNodeContainsRegion(allDataNodeId, regionMap, selectedRegion); + regionGroupShrink(statement, client, selectedRegion, targetDataNode); + // update regionMap every time + regionMap = getAllRegionMap(statement); + } + } + } + } + + private void regionGroupExpand( + Statement statement, + SyncConfigNodeIServiceClient client, + int selectedRegion, + int targetDataNode) + throws Exception { + statement.execute(String.format(EXPAND_FORMAT, selectedRegion, targetDataNode)); + + Predicate expandRegionPredicate = + tShowRegionResp -> { + Map> newRegionMap = + getRunningRegionMap(tShowRegionResp.getRegionInfoList()); + Set dataNodes = newRegionMap.get(selectedRegion); + return dataNodes.contains(targetDataNode); + }; + + awaitUntilSuccess(client, expandRegionPredicate, Optional.of(targetDataNode), Optional.empty()); + + LOGGER.info("Region {} has expanded to DataNode {}", selectedRegion, targetDataNode); + } + + private void regionGroupShrink( + Statement statement, + SyncConfigNodeIServiceClient client, + int selectedRegion, + int targetDataNode) + throws Exception { + statement.execute(String.format(SHRINK_FORMAT, selectedRegion, targetDataNode)); + + Predicate shrinkRegionPredicate = + tShowRegionResp -> { + Map> newRegionMap = + getRegionMap(tShowRegionResp.getRegionInfoList()); + Set dataNodes = newRegionMap.get(selectedRegion); + return !dataNodes.contains(targetDataNode); + }; + + awaitUntilSuccess(client, shrinkRegionPredicate, Optional.empty(), Optional.of(targetDataNode)); + + LOGGER.info("Region {} has shrunk from DataNode {}", selectedRegion, targetDataNode); + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionReconstructForIoTV1IT.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionReconstructForIoTV1IT.java new file mode 100644 index 000000000000..08a4db981382 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/IoTDBRegionReconstructForIoTV1IT.java @@ -0,0 +1,141 @@ +/* + * 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.regionmigration.pass.commit; + +import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; +import org.apache.iotdb.commons.cluster.NodeStatus; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; +import org.apache.iotdb.consensus.ConsensusFactory; +import org.apache.iotdb.isession.SessionDataSet; +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.ClusterIT; +import org.apache.iotdb.rpc.StatementExecutionException; +import org.apache.iotdb.session.Session; + +import org.apache.commons.io.FileUtils; +import org.apache.tsfile.read.common.RowRecord; +import org.awaitility.Awaitility; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.sql.Connection; +import java.sql.Statement; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; + +@Category({ClusterIT.class}) +@RunWith(IoTDBTestRunner.class) +public class IoTDBRegionReconstructForIoTV1IT extends IoTDBRegionOperationReliabilityITFramework { + private static final String RECONSTRUCT_FORMAT = "reconstruct region %d on %d"; + private static Logger LOGGER = LoggerFactory.getLogger(IoTDBRegionReconstructForIoTV1IT.class); + + @Test + public void normal1C3DTest() throws Exception { + EnvFactory.getEnv() + .getConfig() + .getCommonConfig() + .setDataRegionConsensusProtocolClass(ConsensusFactory.IOT_CONSENSUS) + .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS) + .setDataReplicationFactor(2) + .setSchemaReplicationFactor(3); + + EnvFactory.getEnv().initClusterEnvironment(1, 3); + + try (Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection()); + Statement statement = makeItCloseQuietly(connection.createStatement()); + SyncConfigNodeIServiceClient client = + (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) { + // prepare data + statement.execute(INSERTION1); + statement.execute(FLUSH_COMMAND); + + // collect necessary information + Map> dataRegionMap = getDataRegionMap(statement); + Set allDataNodeId = getAllDataNodes(statement); + + // select datanode + final int selectedRegion = 1; + Assert.assertTrue(dataRegionMap.containsKey(selectedRegion)); + Assert.assertEquals(2, dataRegionMap.get(selectedRegion).size()); + Iterator iterator = dataRegionMap.get(selectedRegion).iterator(); + final int dataNodeToBeClosed = iterator.next(); + final int dataNodeToBeReconstructed = iterator.next(); + final int dataNodeAlwaysGood = + allDataNodeId.stream() + .filter(x -> x != dataNodeToBeReconstructed && x != dataNodeToBeClosed) + .findAny() + .get(); + final DataNodeWrapper dataNodeWrapper = + EnvFactory.getEnv().dataNodeIdToWrapper(dataNodeAlwaysGood).get(); + Session session = + new Session.Builder() + .host(dataNodeWrapper.getIp()) + .port(dataNodeWrapper.getPort()) + .build(); + session.open(); + + // delete one DataNode's data dir, stop another DataNode + File dataDirToBeReconstructed = + new File( + EnvFactory.getEnv() + .dataNodeIdToWrapper(dataNodeToBeReconstructed) + .get() + .getDataPath()); + FileUtils.deleteDirectory(dataDirToBeReconstructed); + EnvFactory.getEnv().dataNodeIdToWrapper(dataNodeToBeClosed).get().stopForcibly(); + + // now, the query should throw exception + Assert.assertThrows( + StatementExecutionException.class, + () -> session.executeQueryStatement("select * from root.**")); + + // start DataNode, reconstruct the delete one + EnvFactory.getEnv().dataNodeIdToWrapper(dataNodeToBeClosed).get().start(); + EnvFactory.getAbstractEnv().checkNodeInStatus(dataNodeToBeClosed, NodeStatus.Running); + session.executeNonQueryStatement( + String.format(RECONSTRUCT_FORMAT, selectedRegion, dataNodeToBeReconstructed)); + Awaitility.await() + .pollInterval(1, TimeUnit.SECONDS) + .atMost(1, TimeUnit.MINUTES) + .until( + () -> + getRegionStatusWithoutRunning(session).isEmpty() + && dataDirToBeReconstructed.exists()); + EnvFactory.getEnv().dataNodeIdToWrapper(dataNodeToBeClosed).get().stopForcibly(); + + // now, the query should work fine + SessionDataSet resultSet = session.executeQueryStatement("select * from root.**"); + RowRecord rowRecord = resultSet.next(); + Assert.assertEquals("2.0", rowRecord.getField(0).getStringValue()); + Assert.assertEquals("1.0", rowRecord.getField(1).getStringValue()); + } + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateNormalITForIoTV2Batch.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateNormalITForIoTV2Batch.java index fed2a6629787..1b1c6edaaad2 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateNormalITForIoTV2Batch.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateNormalITForIoTV2Batch.java @@ -20,7 +20,7 @@ package org.apache.iotdb.confignode.it.regionmigration.pass.commit.batch; import org.apache.iotdb.commons.utils.KillPoint.KillNode; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; @@ -31,7 +31,7 @@ @Category({ClusterIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateNormalITForIoTV2Batch - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Test public void normal1C2DTest() throws Exception { successTest(1, 1, 1, 2, noKillPoints(), noKillPoints(), KillNode.ALL_NODES); diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateOtherITForIoTV2Batch.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateOtherITForIoTV2Batch.java index a99b49c30ce1..e18f0140e0ee 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateOtherITForIoTV2Batch.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/batch/IoTDBRegionMigrateOtherITForIoTV2Batch.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; import org.apache.iotdb.commons.utils.KillPoint.NeverTriggeredKillPoint; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; @@ -33,7 +33,7 @@ @RunWith(IoTDBTestRunner.class) @Category({ClusterIT.class}) public class IoTDBRegionMigrateOtherITForIoTV2Batch - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Test public void badKillPoint() throws Exception { try { diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateNormalITForIoTV2Stream.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateNormalITForIoTV2Stream.java index afba878bd39a..095002a214d6 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateNormalITForIoTV2Stream.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateNormalITForIoTV2Stream.java @@ -20,7 +20,7 @@ package org.apache.iotdb.confignode.it.regionmigration.pass.commit.stream; import org.apache.iotdb.commons.utils.KillPoint.KillNode; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -34,7 +34,7 @@ @Category({ClusterIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateNormalITForIoTV2Stream - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateOtherITForIoTV2Stream.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateOtherITForIoTV2Stream.java index 9406f2f2fcbe..a246aac8327e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateOtherITForIoTV2Stream.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/commit/stream/IoTDBRegionMigrateOtherITForIoTV2Stream.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; import org.apache.iotdb.commons.utils.KillPoint.NeverTriggeredKillPoint; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -36,7 +36,7 @@ @RunWith(IoTDBTestRunner.class) @Category({ClusterIT.class}) public class IoTDBRegionMigrateOtherITForIoTV2Stream - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv1/IoTDBRegionMigrateDataNodeCrashForIoTV1IT.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv1/IoTDBRegionMigrateDataNodeCrashForIoTV1IT.java index 704ae82af3c9..50beb4ec5493 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv1/IoTDBRegionMigrateDataNodeCrashForIoTV1IT.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv1/IoTDBRegionMigrateDataNodeCrashForIoTV1IT.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.DataNodeKillPoints; import org.apache.iotdb.commons.utils.KillPoint.KillNode; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -35,7 +35,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateDataNodeCrashForIoTV1IT - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { // region Coordinator DataNode crash tests private final int dataReplicateFactor = 2; diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/batch/IoTDBRegionMigrateDataNodeCrashForIoTV2Batch.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/batch/IoTDBRegionMigrateDataNodeCrashForIoTV2Batch.java index 4938ed6d8b83..16b9819301a0 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/batch/IoTDBRegionMigrateDataNodeCrashForIoTV2Batch.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/batch/IoTDBRegionMigrateDataNodeCrashForIoTV2Batch.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.DataNodeKillPoints; import org.apache.iotdb.commons.utils.KillPoint.KillNode; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.DailyIT; @@ -32,7 +32,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateDataNodeCrashForIoTV2Batch - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { // region Coordinator DataNode crash tests private final int dataReplicateFactor = 2; diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/stream/IoTDBRegionMigrateDataNodeCrashForIoTV2Stream.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/stream/IoTDBRegionMigrateDataNodeCrashForIoTV2Stream.java index adadc8d0de9f..e6a39210b592 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/stream/IoTDBRegionMigrateDataNodeCrashForIoTV2Stream.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/datanodecrash/iotv2/stream/IoTDBRegionMigrateDataNodeCrashForIoTV2Stream.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.DataNodeKillPoints; import org.apache.iotdb.commons.utils.KillPoint.KillNode; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -35,7 +35,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateDataNodeCrashForIoTV2Stream - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { // region Coordinator DataNode crash tests private final int dataReplicateFactor = 2; diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateClusterCrashIoTV1IT.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateClusterCrashIoTV1IT.java index 7f2bfb3066b2..544c4b568170 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateClusterCrashIoTV1IT.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateClusterCrashIoTV1IT.java @@ -19,7 +19,7 @@ package org.apache.iotdb.confignode.it.regionmigration.pass.daily.iotv1; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; import org.apache.iotdb.consensus.ConsensusFactory; @@ -35,7 +35,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateClusterCrashIoTV1IT - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateConfigNodeCrashIoTV1IT.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateConfigNodeCrashIoTV1IT.java index e63ded6baf42..ebda0c36ee32 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateConfigNodeCrashIoTV1IT.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv1/IoTDBRegionMigrateConfigNodeCrashIoTV1IT.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; import org.apache.iotdb.commons.utils.KillPoint.KillPoint; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RegionTransitionState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; @@ -43,7 +43,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateConfigNodeCrashIoTV1IT - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateClusterCrashIoTV2Batch.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateClusterCrashIoTV2Batch.java index faf1c21778fb..36d7598dcee4 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateClusterCrashIoTV2Batch.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateClusterCrashIoTV2Batch.java @@ -19,7 +19,7 @@ package org.apache.iotdb.confignode.it.regionmigration.pass.daily.iotv2.batch; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -32,7 +32,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateClusterCrashIoTV2Batch - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Test public void clusterCrash1() throws Exception { diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateConfigNodeCrashIoTV2Batch.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateConfigNodeCrashIoTV2Batch.java index f3fa4a055ead..5dc3a303628f 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateConfigNodeCrashIoTV2Batch.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/batch/IoTDBRegionMigrateConfigNodeCrashIoTV2Batch.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; import org.apache.iotdb.commons.utils.KillPoint.KillPoint; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RegionTransitionState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; @@ -40,7 +40,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateConfigNodeCrashIoTV2Batch - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Test @Ignore public void cnCrashDuringPreCheckTest() throws Exception { diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateClusterCrashIoTV2Stream.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateClusterCrashIoTV2Stream.java index 4c11e39cf8d3..951ff951ec34 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateClusterCrashIoTV2Stream.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateClusterCrashIoTV2Stream.java @@ -19,7 +19,7 @@ package org.apache.iotdb.confignode.it.regionmigration.pass.daily.iotv2.stream; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; import org.apache.iotdb.consensus.ConsensusFactory; @@ -35,7 +35,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateClusterCrashIoTV2Stream - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateConfigNodeCrashIoTV2Stream.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateConfigNodeCrashIoTV2Stream.java index d7c1a14d19bf..66fe3566b25d 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateConfigNodeCrashIoTV2Stream.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/regionmigration/pass/daily/iotv2/stream/IoTDBRegionMigrateConfigNodeCrashIoTV2Stream.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.utils.KillPoint.KillNode; import org.apache.iotdb.commons.utils.KillPoint.KillPoint; -import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework; +import org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.state.RegionTransitionState; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; @@ -43,7 +43,7 @@ @Category({DailyIT.class}) @RunWith(IoTDBTestRunner.class) public class IoTDBRegionMigrateConfigNodeCrashIoTV2Stream - extends IoTDBRegionMigrateReliabilityITFramework { + extends IoTDBRegionOperationReliabilityITFramework { @Override @Before diff --git a/integration-test/src/test/java/org/apache/iotdb/confignode/it/removedatanode/IoTDBRemoveDataNodeITFramework.java b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removedatanode/IoTDBRemoveDataNodeITFramework.java index 5082c7beda01..8ae9cdba714a 100644 --- a/integration-test/src/test/java/org/apache/iotdb/confignode/it/removedatanode/IoTDBRemoveDataNodeITFramework.java +++ b/integration-test/src/test/java/org/apache/iotdb/confignode/it/removedatanode/IoTDBRemoveDataNodeITFramework.java @@ -51,8 +51,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework.closeQuietly; -import static org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework.getRegionMap; +import static org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionOperationReliabilityITFramework.getDataRegionMap; +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; public class IoTDBRemoveDataNodeITFramework { private static final Logger LOGGER = @@ -143,16 +143,15 @@ public void testRemoveDataNode( dataRegionPerDataNode * dataNodeNum / dataReplicateFactor); EnvFactory.getEnv().initClusterEnvironment(configNodeNum, dataNodeNum); - try (final Connection connection = closeQuietly(EnvFactory.getEnv().getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); + try (final Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement()); SyncConfigNodeIServiceClient client = (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) { // Insert data statement.execute(INSERTION1); - ResultSet result = statement.executeQuery(SHOW_REGIONS); - Map> regionMap = getRegionMap(result); + Map> regionMap = getDataRegionMap(statement); regionMap.forEach( (key, valueSet) -> { LOGGER.info("Key: {}, Value: {}", key, valueSet); @@ -162,7 +161,7 @@ public void testRemoveDataNode( }); // Get all data nodes - result = statement.executeQuery(SHOW_DATANODES); + ResultSet result = statement.executeQuery(SHOW_DATANODES); Set allDataNodeId = new HashSet<>(); while (result.next()) { allDataNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID)); @@ -238,12 +237,11 @@ public void testRemoveDataNode( LOGGER.error("Unexpected error:", e); } - try (final Connection connection = closeQuietly(EnvFactory.getEnv().getConnection()); - final Statement statement = closeQuietly(connection.createStatement())) { + try (final Connection connection = makeItCloseQuietly(EnvFactory.getEnv().getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement())) { // Check the data region distribution after removing data nodes - ResultSet result = statement.executeQuery(SHOW_REGIONS); - Map> afterRegionMap = getRegionMap(result); + Map> afterRegionMap = getDataRegionMap(statement); afterRegionMap.forEach( (key, valueSet) -> { LOGGER.info("Key: {}, Value: {}", key, valueSet); @@ -253,7 +251,7 @@ public void testRemoveDataNode( }); if (rejoinRemovedDataNode) { - result = statement.executeQuery(SHOW_DATANODES); + ResultSet result = statement.executeQuery(SHOW_DATANODES); Set allDataNodeId = new HashSet<>(); while (result.next()) { allDataNodeId.add(result.getInt(ColumnHeaderConstant.NODE_ID)); diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java index 72b40c5c9dc4..8de2d3c7e002 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java @@ -256,8 +256,7 @@ public void testIllegalFilePath() { String errorMsg1 = TSStatusCode.SQL_PARSE_ERROR.getStatusCode() - + ": Error occurred while parsing SQL to physical plan: " - + "line 1:7 mismatched input 'path' expecting STRING_LITERAL"; + + ": Error occurred while parsing SQL to physical plan: line 1:7 no viable alternative at input 'REMOVE path'"; try (Connection connection = EnvFactory.getEnv().getConnection(); Statement statement = connection.createStatement()) { statement.execute("REMOVE path"); diff --git a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeAutoDropIT.java b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeAutoDropIT.java index c30006a73f4d..adff5e5f53da 100644 --- a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeAutoDropIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeAutoDropIT.java @@ -43,7 +43,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework.closeQuietly; +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; import static org.awaitility.Awaitility.await; @RunWith(IoTDBTestRunner.class) @@ -93,8 +93,8 @@ public void testAutoDropInHistoricalTransfer() throws Exception { "count(root.db.d1.s1),", Collections.singleton("1,")); - try (final Connection connection = closeQuietly(senderEnv.getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); ) { + try (final Connection connection = makeItCloseQuietly(senderEnv.getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement()); ) { ResultSet result = statement.executeQuery("show pipes"); await() .pollInSameThread() @@ -168,8 +168,8 @@ public void testAutoDropInHistoricalTransferWithTimeRange() throws Exception { "count(root.db.d1.s1),", Collections.singleton("3,")); - try (final Connection connection = closeQuietly(senderEnv.getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); ) { + try (final Connection connection = makeItCloseQuietly(senderEnv.getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement()); ) { ResultSet result = statement.executeQuery("show pipes"); await() .pollInSameThread() diff --git a/integration-test/src/test/java/org/apache/iotdb/pipe/it/tablemodel/IoTDBPipeAutoDropIT.java b/integration-test/src/test/java/org/apache/iotdb/pipe/it/tablemodel/IoTDBPipeAutoDropIT.java index bae1dda7a739..8f19b7f32a7f 100644 --- a/integration-test/src/test/java/org/apache/iotdb/pipe/it/tablemodel/IoTDBPipeAutoDropIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/pipe/it/tablemodel/IoTDBPipeAutoDropIT.java @@ -44,7 +44,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import static org.apache.iotdb.confignode.it.regionmigration.IoTDBRegionMigrateReliabilityITFramework.closeQuietly; +import static org.apache.iotdb.util.MagicUtils.makeItCloseQuietly; import static org.awaitility.Awaitility.await; @RunWith(IoTDBTestRunner.class) @@ -105,8 +105,8 @@ public void testAutoDropInHistoricalTransfer() throws Exception { handleFailure); } - try (final Connection connection = closeQuietly(senderEnv.getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); ) { + try (final Connection connection = makeItCloseQuietly(senderEnv.getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement()); ) { ResultSet result = statement.executeQuery("show pipes"); await() .pollInSameThread() @@ -187,8 +187,8 @@ public void testAutoDropInHistoricalTransferWithTimeRange() throws Exception { handleFailure); } - try (final Connection connection = closeQuietly(senderEnv.getConnection()); - final Statement statement = closeQuietly(connection.createStatement()); ) { + try (final Connection connection = makeItCloseQuietly(senderEnv.getConnection()); + final Statement statement = makeItCloseQuietly(connection.createStatement()); ) { ResultSet result = statement.executeQuery("show pipes"); await() .pollInSameThread() diff --git a/integration-test/src/test/java/org/apache/iotdb/util/MagicUtils.java b/integration-test/src/test/java/org/apache/iotdb/util/MagicUtils.java new file mode 100644 index 000000000000..e6213a72b71b --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/util/MagicUtils.java @@ -0,0 +1,61 @@ +/* + * 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.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Proxy; + +public class MagicUtils { + + private static Logger LOGGER = LoggerFactory.getLogger(MagicUtils.class); + + /** + * Ignore all exceptions during close() + * + * @param t target object + * @return object which will close without exception + */ + public static T makeItCloseQuietly(T t) { + InvocationHandler handler = + (proxy, method, args) -> { + try { + if (method.getName().equals("close")) { + try { + method.invoke(t, args); + } catch (Throwable e) { + LOGGER.warn("Exception happens during close(): ", e); + } + return null; + } else { + return method.invoke(t, args); + } + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + }; + return (T) + Proxy.newProxyInstance( + t.getClass().getClassLoader(), t.getClass().getInterfaces(), handler); + } +} diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java index b1863c3d491e..b68215cd37fd 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java @@ -172,6 +172,9 @@ public enum TSStatusCode { REGION_LEADER_CHANGE_ERROR(905), NO_AVAILABLE_REGION_GROUP(906), LACK_PARTITION_ALLOCATION(907), + RECONSTRUCT_REGION_ERROR(908), + EXTEND_REGION_ERROR(909), + REMOVE_REGION_PEER_ERROR(910), // Cluster Manager ADD_CONFIGNODE_ERROR(1000), 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 9fe797cb82c7..13d9cc6708dc 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 @@ -62,7 +62,9 @@ ddlStatement | createContinuousQuery | dropContinuousQuery | showContinuousQueries // Cluster | showVariables | showCluster | showRegions | showDataNodes | showConfigNodes | showClusterId - | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList | migrateRegion | verifyConnection + | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList + | migrateRegion | reconstructRegion | extendRegion | removeRegion + | verifyConnection // AINode | showAINodes | createModel | dropModel | showModels | callInference // Quota @@ -532,6 +534,18 @@ migrateRegion : MIGRATE REGION regionId=INTEGER_LITERAL FROM fromId=INTEGER_LITERAL TO toId=INTEGER_LITERAL ; +reconstructRegion + : RECONSTRUCT REGION regionIds+=INTEGER_LITERAL (COMMA regionIds+=INTEGER_LITERAL)* ON targetDataNodeId=INTEGER_LITERAL + ; + +extendRegion + : EXTEND REGION regionId=INTEGER_LITERAL TO targetDataNodeId=INTEGER_LITERAL + ; + +removeRegion + : REMOVE REGION regionId=INTEGER_LITERAL FROM targetDataNodeId=INTEGER_LITERAL + ; + verifyConnection : VERIFY CONNECTION (DETAILS)? ; 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 a2803be52a41..50f957c7fcc2 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 @@ -302,6 +302,10 @@ EXPLAIN : E X P L A I N ; +EXTEND + : E X T E N D + ; + EXTRACTOR : E X T R A C T O R ; @@ -642,6 +646,10 @@ READONLY : R E A D O N L Y ; +RECONSTRUCT + : R E C O N S T R U C T + ; + REGEXP : R E G E X P ; 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 d1006aaba6ff..0baa745c0345 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 @@ -171,6 +171,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDropPipeReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTopicReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TFetchTableResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllPipeInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllSubscriptionInfoResp; @@ -201,7 +202,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferResp; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp; import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionTableResp; import org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq; @@ -2379,6 +2382,30 @@ public TSStatus migrateRegion(TMigrateRegionReq req) { : status; } + @Override + public TSStatus reconstructRegion(TReconstructRegionReq req) { + TSStatus status = confirmLeader(); + return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode() + ? procedureManager.reconstructRegion(req) + : status; + } + + @Override + public TSStatus extendRegion(TExtendRegionReq req) { + TSStatus status = confirmLeader(); + return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode() + ? procedureManager.extendRegion(req) + : status; + } + + @Override + public TSStatus removeRegion(TRemoveRegionReq req) { + TSStatus status = confirmLeader(); + return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode() + ? procedureManager.removeRegion(req) + : status; + } + @Override public TSStatus createCQ(TCreateCQReq req) { TSStatus status = confirmLeader(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java index 779f3daa03b8..6fcc8b3bc835 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java @@ -95,6 +95,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDropPipeReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTopicReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TFetchTableResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllPipeInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllSubscriptionInfoResp; @@ -124,7 +125,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferResp; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp; import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionTableResp; import org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq; @@ -810,6 +813,12 @@ TDataPartitionTableResp getOrCreateDataPartition( TSStatus migrateRegion(TMigrateRegionReq req); + TSStatus reconstructRegion(TReconstructRegionReq req); + + TSStatus extendRegion(TExtendRegionReq req); + + TSStatus removeRegion(TRemoveRegionReq req); + TSStatus createCQ(TCreateCQReq req); TSStatus dropCQ(TDropCQReq req); 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 b26b8c6b3beb..6ef3a3d2945f 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 @@ -74,9 +74,13 @@ import org.apache.iotdb.confignode.procedure.impl.pipe.task.DropPipeProcedureV2; import org.apache.iotdb.confignode.procedure.impl.pipe.task.StartPipeProcedureV2; import org.apache.iotdb.confignode.procedure.impl.pipe.task.StopPipeProcedureV2; +import org.apache.iotdb.confignode.procedure.impl.region.AddRegionPeerProcedure; import org.apache.iotdb.confignode.procedure.impl.region.CreateRegionGroupsProcedure; +import org.apache.iotdb.confignode.procedure.impl.region.ReconstructRegionProcedure; import org.apache.iotdb.confignode.procedure.impl.region.RegionMigrateProcedure; import org.apache.iotdb.confignode.procedure.impl.region.RegionMigrationPlan; +import org.apache.iotdb.confignode.procedure.impl.region.RegionOperationProcedure; +import org.apache.iotdb.confignode.procedure.impl.region.RemoveRegionPeerProcedure; import org.apache.iotdb.confignode.procedure.impl.schema.AlterLogicalViewProcedure; import org.apache.iotdb.confignode.procedure.impl.schema.DeactivateTemplateProcedure; import org.apache.iotdb.confignode.procedure.impl.schema.DeleteDatabaseProcedure; @@ -126,7 +130,10 @@ import org.apache.iotdb.confignode.rpc.thrift.TDeleteTableDeviceReq; import org.apache.iotdb.confignode.rpc.thrift.TDeleteTableDeviceResp; import org.apache.iotdb.confignode.rpc.thrift.TDropPipePluginReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TMigrateRegionReq; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TSubscribeReq; import org.apache.iotdb.confignode.rpc.thrift.TUnsubscribeReq; import org.apache.iotdb.consensus.ConsensusFactory; @@ -135,6 +142,7 @@ import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; +import org.apache.ratis.util.AutoCloseableLock; import org.apache.tsfile.utils.Binary; import org.apache.tsfile.utils.Pair; import org.apache.tsfile.utils.ReadWriteIOUtils; @@ -157,8 +165,6 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import static org.apache.iotdb.confignode.conf.ConfigNodeConstant.REGION_MIGRATE_PROCESS; - public class ProcedureManager { private static final Logger LOGGER = LoggerFactory.getLogger(ProcedureManager.class); @@ -608,8 +614,7 @@ public TSStatus checkRemoveDataNodes(List dataNodeLocations) if (regionMigrateProcedure.isFinished()) { return false; } - return removedDataNodesRegionSet.contains( - regionMigrateProcedure.getConsensusGroupId()) + return removedDataNodesRegionSet.contains(regionMigrateProcedure.getRegionId()) || dataNodeLocations.contains(regionMigrateProcedure.getDestDataNode()); } return false; @@ -623,7 +628,7 @@ public TSStatus checkRemoveDataNodes(List dataNodeLocations) + "The RegionMigrateProcedure is migrating the region %s to the DataNode %s. " + "For further information, please search [pid%d] in log. ", conflictRegionMigrateProcedure.get().getProcId(), - ((RegionMigrateProcedure) conflictRegionMigrateProcedure.get()).getConsensusGroupId(), + ((RegionMigrateProcedure) conflictRegionMigrateProcedure.get()).getRegionId(), ((RegionMigrateProcedure) conflictRegionMigrateProcedure.get()).getDestDataNode(), conflictRegionMigrateProcedure.get().getProcId()); } @@ -678,6 +683,8 @@ public TSStatus checkRemoveDataNodes(List dataNodeLocations) return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); } + // region region operation related check + /** * Checks whether region migration is allowed. * @@ -688,61 +695,21 @@ public TSStatus checkRemoveDataNodes(List dataNodeLocations) * @param coordinatorForAddPeer the DataNode location acting as the coordinator for adding a peer * @return the status of the migration request (TSStatus) */ - private TSStatus checkRegionMigrate( + private TSStatus checkMigrateRegion( TMigrateRegionReq migrateRegionReq, TConsensusGroupId regionGroupId, TDataNodeLocation originalDataNode, TDataNodeLocation destDataNode, TDataNodeLocation coordinatorForAddPeer) { - String failMessage = null; - // 1. Check if the RegionMigrateProcedure has conflict with another RegionMigrateProcedure - Optional> anotherMigrateProcedure = - getExecutor().getProcedures().values().stream() - .filter( - procedure -> { - if (procedure instanceof RegionMigrateProcedure) { - return !procedure.isFinished() - && ((RegionMigrateProcedure) procedure) - .getConsensusGroupId() - .equals(regionGroupId); - } - return false; - }) - .findAny(); - ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf(); - if (TConsensusGroupType.DataRegion == regionGroupId.getType() - && ConsensusFactory.SIMPLE_CONSENSUS.equals(conf.getDataRegionConsensusProtocolClass())) { - failMessage = - "The region you are trying to migrate is using SimpleConsensus, and SimpleConsensus not supports region migration."; - } else if (TConsensusGroupType.SchemaRegion == regionGroupId.getType() - && ConsensusFactory.SIMPLE_CONSENSUS.equals(conf.getSchemaRegionConsensusProtocolClass())) { - failMessage = - "The region you are trying to migrate is using SimpleConsensus, and SimpleConsensus not supports region migration."; - } else if (anotherMigrateProcedure.isPresent()) { - failMessage = - String.format( - "Submit RegionMigrateProcedure failed, " - + "because another RegionMigrateProcedure of the same consensus group %d is already in processing. " - + "A consensus group is able to have at most 1 RegionMigrateProcedure at the same time. " - + "For further information, please search [pid%d] in log. ", - regionGroupId.getId(), anotherMigrateProcedure.get().getProcId()); - } else if (originalDataNode == null) { - failMessage = - String.format( - "Submit RegionMigrateProcedure failed, because no original DataNode %d", - migrateRegionReq.getFromId()); - } else if (destDataNode == null) { - failMessage = - String.format( - "Submit RegionMigrateProcedure failed, because no target DataNode %s", - migrateRegionReq.getToId()); - } else if (coordinatorForAddPeer == null) { - failMessage = - String.format( - "%s, There are no other DataNodes could be selected to perform the add peer process, " - + "please check RegionGroup: %s by show regions sql command", - REGION_MIGRATE_PROCESS, regionGroupId); - } else if (configManager + String failMessage = + regionOperationCommonCheck( + regionGroupId, + destDataNode, + Arrays.asList( + new Pair<>("Original DataNode", originalDataNode), + new Pair<>("Destination DataNode", destDataNode), + new Pair<>("Coordinator for add peer", coordinatorForAddPeer))); + if (configManager .getPartitionManager() .getAllReplicaSets(originalDataNode.getDataNodeId()) .stream() @@ -760,23 +727,179 @@ private TSStatus checkRegionMigrate( String.format( "Submit RegionMigrateProcedure failed, because the target DataNode %s already contains Region %s", migrateRegionReq.getToId(), migrateRegionReq.getRegionId()); - } else if (!configManager - .getNodeManager() - .filterDataNodeThroughStatus(NodeStatus.Running) + } + + if (failMessage != null) { + LOGGER.warn(failMessage); + TSStatus failStatus = new TSStatus(TSStatusCode.MIGRATE_REGION_ERROR.getStatusCode()); + failStatus.setMessage(failMessage); + return failStatus; + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + + private TSStatus checkReconstructRegion( + TReconstructRegionReq req, + TConsensusGroupId regionId, + TDataNodeLocation targetDataNode, + TDataNodeLocation coordinator) { + String failMessage = + regionOperationCommonCheck( + regionId, + targetDataNode, + Arrays.asList( + new Pair<>("Target DataNode", targetDataNode), + new Pair<>("Coordinator", coordinator))); + + ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf(); + if (configManager + .getPartitionManager() + .getAllReplicaSetsMap(regionId.getType()) + .get(regionId) + .getDataNodeLocationsSize() + == 1) { + failMessage = String.format("%s only has 1 replica, it cannot be reconstructed", regionId); + } else if (configManager + .getPartitionManager() + .getAllReplicaSets(targetDataNode.getDataNodeId()) + .stream() + .noneMatch(replicaSet -> replicaSet.getRegionId().equals(regionId))) { + failMessage = + String.format( + "Submit ReconstructRegionProcedure failed, because the target DataNode %s doesn't contain Region %s", + req.getDataNodeId(), regionId); + } + + if (failMessage != null) { + LOGGER.warn(failMessage); + TSStatus failStatus = new TSStatus(TSStatusCode.RECONSTRUCT_REGION_ERROR.getStatusCode()); + failStatus.setMessage(failMessage); + return failStatus; + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + + private TSStatus checkExtendRegion( + TExtendRegionReq req, + TConsensusGroupId regionId, + TDataNodeLocation targetDataNode, + TDataNodeLocation coordinator) { + String failMessage = + regionOperationCommonCheck( + regionId, + targetDataNode, + Arrays.asList( + new Pair<>("Target DataNode", targetDataNode), + new Pair<>("Coordinator", coordinator))); + if (configManager + .getPartitionManager() + .getAllReplicaSets(targetDataNode.getDataNodeId()) + .stream() + .anyMatch(replicaSet -> replicaSet.getRegionId().equals(regionId))) { + failMessage = + String.format( + "Target DataNode %s already contains region %s", + targetDataNode.getDataNodeId(), req.getRegionId()); + } + + if (failMessage != null) { + LOGGER.warn(failMessage); + TSStatus failStatus = new TSStatus(TSStatusCode.RECONSTRUCT_REGION_ERROR.getStatusCode()); + failStatus.setMessage(failMessage); + return failStatus; + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + + private TSStatus checkRemoveRegion( + TRemoveRegionReq req, + TConsensusGroupId regionId, + TDataNodeLocation targetDataNode, + TDataNodeLocation coordinator) { + String failMessage = + regionOperationCommonCheck( + regionId, + targetDataNode, + Arrays.asList( + new Pair<>("Target DataNode", targetDataNode), + new Pair<>("Coordinator", coordinator))); + + ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf(); + if (configManager + .getPartitionManager() + .getAllReplicaSetsMap(regionId.getType()) + .get(regionId) + .getDataNodeLocationsSize() + == 1) { + failMessage = String.format("%s only has 1 replica, it cannot be removed", regionId); + } else if (configManager + .getPartitionManager() + .getAllReplicaSets(targetDataNode.getDataNodeId()) .stream() - .map(TDataNodeConfiguration::getLocation) - .map(TDataNodeLocation::getDataNodeId) - .collect(Collectors.toSet()) - .contains(migrateRegionReq.getToId())) { + .noneMatch(replicaSet -> replicaSet.getRegionId().equals(regionId))) { + failMessage = + String.format( + "Target DataNode %s doesn't contain Region %s", req.getDataNodeId(), regionId); + } + + if (failMessage != null) { + LOGGER.warn(failMessage); + TSStatus failStatus = new TSStatus(TSStatusCode.REMOVE_REGION_PEER_ERROR.getStatusCode()); + failStatus.setMessage(failMessage); + return failStatus; + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + + /** + * The common checks of all region operations, include migration, reconstruction, extension, + * removing + * + * @param regionId region group id, also called consensus group id + * @param targetDataNode DataNode should in Running status + * @param relatedDataNodes Pair + * @return The reason if check failed, or null if check pass + */ + private String regionOperationCommonCheck( + TConsensusGroupId regionId, + TDataNodeLocation targetDataNode, + List> relatedDataNodes) { + String failMessage; + + ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf(); + if (TConsensusGroupType.DataRegion == regionId.getType() + && ConsensusFactory.SIMPLE_CONSENSUS.equals(conf.getDataRegionConsensusProtocolClass())) { + failMessage = "SimpleConsensus not supports region operation."; + } else if (TConsensusGroupType.SchemaRegion == regionId.getType() + && ConsensusFactory.SIMPLE_CONSENSUS.equals(conf.getSchemaRegionConsensusProtocolClass())) { + failMessage = "SimpleConsensus not supports region operation."; + } else if ((failMessage = checkRegionOperationDuplication(regionId)) != null) { + // need to do nothing more + } else if (relatedDataNodes.stream().anyMatch(pair -> pair.getRight() == null)) { + Pair nullPair = + relatedDataNodes.stream().filter(pair -> pair.getRight() == null).findAny().get(); + failMessage = String.format("Cannot find %s", nullPair.getLeft()); + } else if (targetDataNode != null + && !configManager.getNodeManager().filterDataNodeThroughStatus(NodeStatus.Running).stream() + .map(TDataNodeConfiguration::getLocation) + .map(TDataNodeLocation::getDataNodeId) + .collect(Collectors.toSet()) + .contains(targetDataNode.getDataNodeId())) { // Here we only check Running DataNode to implement migration, because removing nodes may not // exist when add peer is performing failMessage = String.format( - "Submit RegionMigrateProcedure failed, because the destDataNode %s is ReadOnly or Unknown.", - migrateRegionReq.getToId()); + "Target DataNode %s is not in Running status.", targetDataNode.getDataNodeId()); + } else if ((failMessage = checkRegionOperationWithRemoveDataNode(regionId, targetDataNode)) + != null) { + // need to do nothing more } - // 2. Check if the RegionMigrateProcedure has conflict with RemoveDataNodesProcedure + return failMessage; + } + + private String checkRegionOperationWithRemoveDataNode( + TConsensusGroupId regionId, TDataNodeLocation targetDataNode) { Optional> conflictRemoveDataNodesProcedure = getExecutor().getProcedures().values().stream() .filter( @@ -794,42 +917,51 @@ private TSStatus checkRegionMigrate( ((RemoveDataNodesProcedure) conflictRemoveDataNodesProcedure.get()).getRemovedDataNodes(); Set removedDataNodesRegionSet = removeDataNodeHandler.getRemovedDataNodesRegionSet(removedDataNodes); - if (removedDataNodesRegionSet.contains(regionGroupId)) { - failMessage = - String.format( - "Submit RegionMigrateProcedure failed, " - + "because another RemoveDataNodesProcedure %s is already in processing which conflicts with this RegionMigrateProcedure. " - + "The RemoveDataNodesProcedure is removing the DataNodes %s which contains the region %s. " - + "For further information, please search [pid%d] in log. ", - conflictRemoveDataNodesProcedure.get().getProcId(), - removedDataNodes, - regionGroupId, - conflictRemoveDataNodesProcedure.get().getProcId()); - } else if (removedDataNodes.contains(destDataNode)) { - failMessage = - String.format( - "Submit RegionMigrateProcedure failed, " - + "because another RemoveDataNodesProcedure %s is already in processing which conflicts with this RegionMigrateProcedure. " - + "The RemoveDataNodesProcedure is removing the target DataNode %s. " - + "For further information, please search [pid%d] in log. ", - conflictRemoveDataNodesProcedure.get().getProcId(), - destDataNode, - conflictRemoveDataNodesProcedure.get().getProcId()); + if (removedDataNodesRegionSet.contains(regionId)) { + return String.format( + "Another RemoveDataNodesProcedure %s is already in processing which conflicts with this procedure. " + + "The RemoveDataNodesProcedure is removing the DataNodes %s which contains the region %s. " + + "For further information, please search [pid%d] in log. ", + conflictRemoveDataNodesProcedure.get().getProcId(), + removedDataNodes, + regionId, + conflictRemoveDataNodesProcedure.get().getProcId()); + } else if (removedDataNodes.contains(targetDataNode)) { + return String.format( + "Another RemoveDataNodesProcedure %s is already in processing which conflicts with this procedure. " + + "The RemoveDataNodesProcedure is removing the target DataNode %s. " + + "For further information, please search [pid%d] in log. ", + conflictRemoveDataNodesProcedure.get().getProcId(), + targetDataNode, + conflictRemoveDataNodesProcedure.get().getProcId()); } } + return null; + } - if (failMessage != null) { - LOGGER.warn(failMessage); - TSStatus failStatus = new TSStatus(TSStatusCode.MIGRATE_REGION_ERROR.getStatusCode()); - failStatus.setMessage(failMessage); - return failStatus; + private String checkRegionOperationDuplication(TConsensusGroupId regionId) { + List> otherRegionMemberChangeProcedures = + getExecutor().getProcedures().values().stream() + .filter(procedure -> !procedure.isFinished()) + .filter(procedure -> procedure instanceof RegionOperationProcedure) + .map(procedure -> (RegionOperationProcedure) procedure) + .filter( + regionMemberChangeProcedure -> + regionId.equals(regionMemberChangeProcedure.getRegionId())) + .collect(Collectors.toList()); + if (!otherRegionMemberChangeProcedures.isEmpty()) { + return String.format( + "%s has some other region operation procedures in progress, their procedure id is: %s", + regionId, otherRegionMemberChangeProcedures); } - return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + return null; } + // end region + public TSStatus migrateRegion(TMigrateRegionReq migrateRegionReq) { - env.getSubmitRegionMigrateLock().lock(); - try { + try (AutoCloseableLock ignoredLock = + AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) { TConsensusGroupId regionGroupId; Optional optional = configManager @@ -871,7 +1003,7 @@ public TSStatus migrateRegion(TMigrateRegionReq migrateRegionReq) { final TDataNodeLocation coordinatorForRemovePeer = destDataNode; TSStatus status = - checkRegionMigrate( + checkMigrateRegion( migrateRegionReq, regionGroupId, originalDataNode, @@ -890,7 +1022,7 @@ public TSStatus migrateRegion(TMigrateRegionReq migrateRegionReq) { coordinatorForAddPeer, coordinatorForRemovePeer)); LOGGER.info( - "Submit RegionMigrateProcedure successfully, Region: {}, Origin DataNode: {}, Dest DataNode: {}, Add Coordinator: {}, Remove Coordinator: {}", + "[MigrateRegion] Submit RegionMigrateProcedure successfully, Region: {}, Origin DataNode: {}, Dest DataNode: {}, Add Coordinator: {}, Remove Coordinator: {}", regionGroupId, originalDataNode, destDataNode, @@ -898,8 +1030,141 @@ public TSStatus migrateRegion(TMigrateRegionReq migrateRegionReq) { coordinatorForRemovePeer); return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); - } finally { - env.getSubmitRegionMigrateLock().unlock(); + } + } + + public TSStatus reconstructRegion(TReconstructRegionReq req) { + RegionMaintainHandler handler = env.getRegionMaintainHandler(); + final TDataNodeLocation targetDataNode = + configManager.getNodeManager().getRegisteredDataNode(req.getDataNodeId()).getLocation(); + try (AutoCloseableLock ignoredLock = + AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) { + List procedures = new ArrayList<>(); + for (int x : req.getRegionIds()) { + TConsensusGroupId regionId = + configManager + .getPartitionManager() + .generateTConsensusGroupIdByRegionId(x) + .orElseThrow(() -> new IllegalArgumentException("Region id " + x + " is invalid")); + final TDataNodeLocation coordinator = + handler + .filterDataNodeWithOtherRegionReplica( + regionId, + targetDataNode, + NodeStatus.Running, + NodeStatus.Removing, + NodeStatus.ReadOnly) + .orElse(null); + TSStatus status = checkReconstructRegion(req, regionId, targetDataNode, coordinator); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + procedures.add(new ReconstructRegionProcedure(regionId, targetDataNode, coordinator)); + } + // all checks pass, submit all procedures + procedures.forEach( + reconstructRegionProcedure -> { + this.executor.submitProcedure(reconstructRegionProcedure); + LOGGER.info( + "[ReconstructRegion] Submit ReconstructRegionProcedure successfully, {}", + reconstructRegionProcedure); + }); + } + return RpcUtils.SUCCESS_STATUS; + } + + public TSStatus extendRegion(TExtendRegionReq req) { + try (AutoCloseableLock ignoredLock = + AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) { + TConsensusGroupId regionId; + Optional optional = + configManager + .getPartitionManager() + .generateTConsensusGroupIdByRegionId(req.getRegionId()); + if (optional.isPresent()) { + regionId = optional.get(); + } else { + LOGGER.error("get region group id fail"); + return new TSStatus(TSStatusCode.EXTEND_REGION_ERROR.getStatusCode()) + .setMessage("get region group id fail"); + } + + // find target dn + final TDataNodeLocation targetDataNode = + configManager.getNodeManager().getRegisteredDataNode(req.getDataNodeId()).getLocation(); + // select coordinator for adding peer + RegionMaintainHandler handler = env.getRegionMaintainHandler(); + // TODO: choose the DataNode which has lowest load + final TDataNodeLocation coordinator = + handler + .filterDataNodeWithOtherRegionReplica( + regionId, + targetDataNode, + NodeStatus.Running, + NodeStatus.Removing, + NodeStatus.ReadOnly) + .orElse(null); + // do the check + TSStatus status = checkExtendRegion(req, regionId, targetDataNode, coordinator); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + // submit procedure + AddRegionPeerProcedure procedure = + new AddRegionPeerProcedure(regionId, coordinator, targetDataNode); + this.executor.submitProcedure(procedure); + LOGGER.info("[ExtendRegion] Submit AddRegionPeerProcedure successfully: {}", procedure); + + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + } + + public TSStatus removeRegion(TRemoveRegionReq req) { + try (AutoCloseableLock ignoredLock = + AutoCloseableLock.acquire(env.getSubmitRegionMigrateLock())) { + TConsensusGroupId regionId; + Optional optional = + configManager + .getPartitionManager() + .generateTConsensusGroupIdByRegionId(req.getRegionId()); + if (optional.isPresent()) { + regionId = optional.get(); + } else { + LOGGER.error("get region group id fail"); + return new TSStatus(TSStatusCode.REMOVE_REGION_PEER_ERROR.getStatusCode()) + .setMessage("get region group id fail"); + } + + // find target dn + final TDataNodeLocation targetDataNode = + configManager.getNodeManager().getRegisteredDataNode(req.getDataNodeId()).getLocation(); + + // select coordinator for removing peer + RegionMaintainHandler handler = env.getRegionMaintainHandler(); + final TDataNodeLocation coordinator = + handler + .filterDataNodeWithOtherRegionReplica( + regionId, + targetDataNode, + NodeStatus.Running, + NodeStatus.Removing, + NodeStatus.ReadOnly) + .orElse(null); + + // do the check + TSStatus status = checkRemoveRegion(req, regionId, targetDataNode, coordinator); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + + // submit procedure + RemoveRegionPeerProcedure procedure = + new RemoveRegionPeerProcedure(regionId, coordinator, targetDataNode); + this.executor.submitProcedure(procedure); + LOGGER.info( + "[RemoveRegionPeer] Submit RemoveRegionPeerProcedure successfully: {}", procedure); + + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java index 1671c696c8fb..2ec8a85acc17 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java @@ -97,7 +97,7 @@ public static String getIdWithRpcEndpoint(TDataNodeLocation location) { location.getDataNodeId(), location.getClientRpcEndPoint()); } - public String simplifiedLocation(TDataNodeLocation dataNodeLocation) { + public static String simplifiedLocation(TDataNodeLocation dataNodeLocation) { return dataNodeLocation.getDataNodeId() + "@" + dataNodeLocation.getInternalEndPoint().getIp(); } @@ -577,12 +577,19 @@ public Optional filterDataNodeWithOtherRegionReplica( configManager.getNodeManager().filterDataNodeThroughStatus(allowingStatus).stream() .map(TDataNodeConfiguration::getLocation) .collect(Collectors.toList()); + final int leaderId = configManager.getLoadManager().getRegionLeaderMap().get(regionId); Collections.shuffle(aliveDataNodes); + Optional bestChoice = Optional.empty(); for (TDataNodeLocation aliveDataNode : aliveDataNodes) { if (regionLocations.contains(aliveDataNode) && !excludeLocations.contains(aliveDataNode)) { - return Optional.of(aliveDataNode); + if (leaderId == aliveDataNode.getDataNodeId()) { + bestChoice = Optional.of(aliveDataNode); + break; + } else if (!bestChoice.isPresent()) { + bestChoice = Optional.of(aliveDataNode); + } } } - return Optional.empty(); + return bestChoice; } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/AddRegionPeerProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/AddRegionPeerProcedure.java index 49e26e7918f3..3da3e0e8abb2 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/AddRegionPeerProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/AddRegionPeerProcedure.java @@ -31,7 +31,6 @@ import org.apache.iotdb.confignode.procedure.exception.ProcedureException; import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; import org.apache.iotdb.confignode.procedure.exception.ProcedureYieldException; -import org.apache.iotdb.confignode.procedure.impl.StateMachineProcedure; import org.apache.iotdb.confignode.procedure.state.AddRegionPeerState; import org.apache.iotdb.confignode.procedure.store.ProcedureType; import org.apache.iotdb.db.utils.DateTimeUtils; @@ -50,17 +49,16 @@ import java.util.stream.Collectors; import static org.apache.iotdb.commons.utils.KillPoint.KillPoint.setKillPoint; +import static org.apache.iotdb.confignode.procedure.env.RegionMaintainHandler.simplifiedLocation; import static org.apache.iotdb.confignode.procedure.state.AddRegionPeerState.UPDATE_REGION_LOCATION_CACHE; import static org.apache.iotdb.rpc.TSStatusCode.SUCCESS_STATUS; -public class AddRegionPeerProcedure - extends StateMachineProcedure { +public class AddRegionPeerProcedure extends RegionOperationProcedure { private static final Logger LOGGER = LoggerFactory.getLogger(AddRegionPeerProcedure.class); - private TConsensusGroupId consensusGroupId; private TDataNodeLocation coordinator; - private TDataNodeLocation destDataNode; + private TDataNodeLocation targetDataNode; public AddRegionPeerProcedure() { super(); @@ -69,17 +67,16 @@ public AddRegionPeerProcedure() { public AddRegionPeerProcedure( TConsensusGroupId consensusGroupId, TDataNodeLocation coordinator, - TDataNodeLocation destDataNode) { - super(); - this.consensusGroupId = consensusGroupId; + TDataNodeLocation targetDataNode) { + super(consensusGroupId); this.coordinator = coordinator; - this.destDataNode = destDataNode; + this.targetDataNode = targetDataNode; } @Override protected Flow executeFromState(ConfigNodeProcedureEnv env, AddRegionPeerState state) throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException { - if (consensusGroupId == null) { + if (regionId == null) { return Flow.NO_MORE_STATE; } RegionMaintainHandler handler = env.getRegionMaintainHandler(); @@ -90,11 +87,11 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, AddRegionPeerState s LOGGER.info( "[pid{}][AddRegion] started, {} will be added to DataNode {}.", getProcId(), - consensusGroupId, - handler.simplifiedLocation(destDataNode)); - handler.addRegionLocation(consensusGroupId, destDataNode); - handler.forceUpdateRegionCache(consensusGroupId, destDataNode, RegionStatus.Adding); - TSStatus status = handler.createNewRegionPeer(consensusGroupId, destDataNode); + regionId, + simplifiedLocation(targetDataNode)); + handler.addRegionLocation(regionId, targetDataNode); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Adding); + TSStatus status = handler.createNewRegionPeer(regionId, targetDataNode); setKillPoint(state); if (status.getCode() != SUCCESS_STATUS.getStatusCode()) { return warnAndRollBackAndNoMoreState(env, handler, "CREATE_NEW_REGION_PEER fail"); @@ -102,12 +99,12 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, AddRegionPeerState s setNextState(AddRegionPeerState.DO_ADD_REGION_PEER); break; case DO_ADD_REGION_PEER: - handler.forceUpdateRegionCache(consensusGroupId, destDataNode, RegionStatus.Adding); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Adding); // We don't want to re-submit AddRegionPeerTask when leader change or ConfigNode reboot if (!this.isStateDeserialized()) { TSStatus tsStatus = handler.submitAddRegionPeerTask( - this.getProcId(), destDataNode, consensusGroupId, coordinator); + this.getProcId(), targetDataNode, regionId, coordinator); setKillPoint(state); if (tsStatus.getCode() != SUCCESS_STATUS.getStatusCode()) { return warnAndRollBackAndNoMoreState( @@ -134,14 +131,14 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, AddRegionPeerState s env, handler, String.format("status %s is unsupported", result.getTaskStatus())); } case UPDATE_REGION_LOCATION_CACHE: - handler.forceUpdateRegionCache(consensusGroupId, destDataNode, RegionStatus.Running); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Running); setKillPoint(state); LOGGER.info("[pid{}][AddRegion] state {} complete", getProcId(), state); LOGGER.info( "[pid{}][AddRegion] success, {} has been added to DataNode {}. Procedure took {} (start at {}).", getProcId(), - consensusGroupId, - handler.simplifiedLocation(destDataNode), + regionId, + simplifiedLocation(targetDataNode), CommonDateTimeUtils.convertMillisecondToDurationStr( System.currentTimeMillis() - getSubmittedTime()), DateTimeUtils.convertLongToDate(getSubmittedTime(), "ms")); @@ -171,18 +168,18 @@ private Flow warnAndRollBackAndNoMoreState( } else { LOGGER.warn("[pid{}][AddRegion] Start to roll back, because: {}", getProcId(), reason); } - handler.removeRegionLocation(consensusGroupId, destDataNode); + handler.removeRegionLocation(regionId, targetDataNode); List correctDataNodeLocations = env.getConfigManager().getPartitionManager().getAllReplicaSets().stream() - .filter(tRegionReplicaSet -> tRegionReplicaSet.getRegionId().equals(consensusGroupId)) + .filter(tRegionReplicaSet -> tRegionReplicaSet.getRegionId().equals(regionId)) .findAny() .orElseThrow( () -> new ProcedureException( "[pid{}][AddRegion] Cannot roll back, because cannot find the correct locations")) .getDataNodeLocations(); - if (correctDataNodeLocations.remove(destDataNode)) { + if (correctDataNodeLocations.remove(targetDataNode)) { LOGGER.warn( "[pid{}][AddRegion] It appears that consensus write has not modified the local partition table. " + "Please verify whether a leader change has occurred during this stage. " @@ -195,7 +192,7 @@ private Flow warnAndRollBackAndNoMoreState( .collect(Collectors.toList()) .toString(); List relatedDataNodeLocations = new ArrayList<>(correctDataNodeLocations); - relatedDataNodeLocations.add(destDataNode); + relatedDataNodeLocations.add(targetDataNode); Map relatedDataNodeLocationMap = relatedDataNodeLocations.stream() .collect( @@ -204,15 +201,14 @@ private Flow warnAndRollBackAndNoMoreState( LOGGER.info( "[pid{}][AddRegion] reset peer list: peer list of consensus group {} on DataNode {} will be reset to {}", getProcId(), - consensusGroupId, + regionId, relatedDataNodeLocationMap.values().stream() .map(TDataNodeLocation::getDataNodeId) .collect(Collectors.toList()), correctStr); Map resultMap = - handler.resetPeerList( - consensusGroupId, correctDataNodeLocations, relatedDataNodeLocationMap); + handler.resetPeerList(regionId, correctDataNodeLocations, relatedDataNodeLocationMap); resultMap.forEach( (dataNodeId, resetResult) -> { @@ -220,7 +216,7 @@ private Flow warnAndRollBackAndNoMoreState( LOGGER.info( "[pid{}][AddRegion] reset peer list: peer list of consensus group {} on DataNode {} has been successfully reset to {}", getProcId(), - consensusGroupId, + regionId, dataNodeId, correctStr); } else { @@ -228,7 +224,7 @@ private Flow warnAndRollBackAndNoMoreState( LOGGER.warn( "[pid{}][AddRegion] reset peer list: peer list of consensus group {} on DataNode {} failed to reset to {}, you may manually reset it", getProcId(), - consensusGroupId, + regionId, dataNodeId, correctStr); } @@ -260,8 +256,8 @@ protected AddRegionPeerState getInitialState() { public void serialize(DataOutputStream stream) throws IOException { stream.writeShort(ProcedureType.ADD_REGION_PEER_PROCEDURE.getTypeCode()); super.serialize(stream); - ThriftCommonsSerDeUtils.serializeTConsensusGroupId(consensusGroupId, stream); - ThriftCommonsSerDeUtils.serializeTDataNodeLocation(destDataNode, stream); + ThriftCommonsSerDeUtils.serializeTConsensusGroupId(regionId, stream); + ThriftCommonsSerDeUtils.serializeTDataNodeLocation(targetDataNode, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(coordinator, stream); } @@ -269,18 +265,14 @@ public void serialize(DataOutputStream stream) throws IOException { public void deserialize(ByteBuffer byteBuffer) { super.deserialize(byteBuffer); try { - consensusGroupId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); - destDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); + regionId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); + targetDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); coordinator = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); } catch (ThriftSerDeException e) { LOGGER.error("Error in deserialize {}", this.getClass(), e); } } - public TConsensusGroupId getConsensusGroupId() { - return consensusGroupId; - } - public TDataNodeLocation getCoordinator() { return coordinator; } @@ -291,13 +283,25 @@ public boolean equals(Object obj) { return false; } AddRegionPeerProcedure procedure = (AddRegionPeerProcedure) obj; - return this.consensusGroupId.equals(procedure.consensusGroupId) - && this.destDataNode.equals(procedure.destDataNode) + return this.regionId.equals(procedure.regionId) + && this.targetDataNode.equals(procedure.targetDataNode) && this.coordinator.equals(procedure.coordinator); } @Override public int hashCode() { - return Objects.hash(consensusGroupId, destDataNode, coordinator); + return Objects.hash(regionId, targetDataNode, coordinator); + } + + @Override + public String toString() { + return "AddRegionPeerProcedure{" + + "regionId=" + + regionId + + ", coordinator=" + + simplifiedLocation(coordinator) + + ", targetDataNode=" + + simplifiedLocation(targetDataNode) + + '}'; } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/ReconstructRegionProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/ReconstructRegionProcedure.java new file mode 100644 index 000000000000..e3ea34718870 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/ReconstructRegionProcedure.java @@ -0,0 +1,209 @@ +/* + * 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.procedure.impl.region; + +import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.commons.exception.runtime.ThriftSerDeException; +import org.apache.iotdb.commons.utils.CommonDateTimeUtils; +import org.apache.iotdb.commons.utils.ThriftCommonsSerDeUtils; +import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; +import org.apache.iotdb.confignode.procedure.exception.ProcedureException; +import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; +import org.apache.iotdb.confignode.procedure.exception.ProcedureYieldException; +import org.apache.iotdb.confignode.procedure.state.ProcedureLockState; +import org.apache.iotdb.confignode.procedure.state.ReconstructRegionState; +import org.apache.iotdb.confignode.procedure.store.ProcedureType; +import org.apache.iotdb.db.utils.DateTimeUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class ReconstructRegionProcedure extends RegionOperationProcedure { + private static final Logger LOGGER = LoggerFactory.getLogger(ReconstructRegionProcedure.class); + + private TDataNodeLocation targetDataNode; + private TDataNodeLocation coordinator; + + public ReconstructRegionProcedure() {} + ; + + public ReconstructRegionProcedure( + TConsensusGroupId regionId, TDataNodeLocation targetDataNode, TDataNodeLocation coordinator) { + super(regionId); + this.targetDataNode = targetDataNode; + this.coordinator = coordinator; + } + + @Override + protected Flow executeFromState(ConfigNodeProcedureEnv env, ReconstructRegionState state) + throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException { + try { + switch (state) { + case RECONSTRUCT_REGION_PREPARE: + LOGGER.info( + "[pid{}][ReconstructRegion] started, region {} on DataNode {}({}) will be reconstructed.", + getProcId(), + regionId.getId(), + targetDataNode.getDataNodeId(), + targetDataNode.getInternalEndPoint()); + setNextState(ReconstructRegionState.REMOVE_REGION_PEER); + break; + case REMOVE_REGION_PEER: + addChildProcedure(new RemoveRegionPeerProcedure(regionId, coordinator, targetDataNode)); + setNextState(ReconstructRegionState.CHECK_REMOVE_REGION_PEER); + break; + case CHECK_REMOVE_REGION_PEER: + if (env.getConfigManager() + .getPartitionManager() + .isDataNodeContainsRegion(targetDataNode.getDataNodeId(), regionId)) { + LOGGER.warn( + "[pid{}][ReconstructRegion] sub-procedure RemoveRegionPeerProcedure failed, ReconstructRegionProcedure will not continue", + getProcId()); + return Flow.NO_MORE_STATE; + } + setNextState(ReconstructRegionState.ADD_REGION_PEER); + break; + case ADD_REGION_PEER: + addChildProcedure(new AddRegionPeerProcedure(regionId, coordinator, targetDataNode)); + setNextState(ReconstructRegionState.CHECK_ADD_REGION_PEER); + break; + case CHECK_ADD_REGION_PEER: + if (!env.getConfigManager() + .getPartitionManager() + .isDataNodeContainsRegion(targetDataNode.getDataNodeId(), regionId)) { + LOGGER.warn( + "[pid{}][ReconstructRegion] failed, but the region {} has been removed from DataNode {}. Use 'extend region' to fix this.", + getProcId(), + regionId.getId(), + targetDataNode.getDataNodeId()); + } else { + LOGGER.info( + "[pid{}][ReconstructRegion] success, region {} has been reconstructed on DataNode {}. Procedure took {} (started at {})", + getProcId(), + regionId.getId(), + targetDataNode.getDataNodeId(), + CommonDateTimeUtils.convertMillisecondToDurationStr( + System.currentTimeMillis() - getSubmittedTime()), + DateTimeUtils.convertLongToDate(getSubmittedTime(), "ms")); + } + return Flow.NO_MORE_STATE; + default: + throw new ProcedureException("Unsupported state: " + state.name()); + } + } catch (Exception e) { + LOGGER.error("[pid{}][ReconstructRegion] state {} fail", getProcId(), state, e); + return Flow.NO_MORE_STATE; + } + LOGGER.info("[pid{}][ReconstructRegion] state {} complete", getProcId(), state); + return Flow.HAS_MORE_STATE; + } + + @Override + protected void rollbackState( + ConfigNodeProcedureEnv configNodeProcedureEnv, ReconstructRegionState reconstructRegionState) + throws IOException, InterruptedException, ProcedureException {} + + @Override + protected ProcedureLockState acquireLock(ConfigNodeProcedureEnv configNodeProcedureEnv) { + configNodeProcedureEnv.getSchedulerLock().lock(); + try { + if (configNodeProcedureEnv.getRegionMigrateLock().tryLock(this)) { + LOGGER.info("procedureId {} acquire lock.", getProcId()); + return ProcedureLockState.LOCK_ACQUIRED; + } + configNodeProcedureEnv.getRegionMigrateLock().waitProcedure(this); + + LOGGER.info("procedureId {} wait for lock.", getProcId()); + return ProcedureLockState.LOCK_EVENT_WAIT; + } finally { + configNodeProcedureEnv.getSchedulerLock().unlock(); + } + } + + @Override + protected void releaseLock(ConfigNodeProcedureEnv configNodeProcedureEnv) { + configNodeProcedureEnv.getSchedulerLock().lock(); + try { + LOGGER.info("procedureId {} release lock.", getProcId()); + if (configNodeProcedureEnv.getRegionMigrateLock().releaseLock(this)) { + configNodeProcedureEnv + .getRegionMigrateLock() + .wakeWaitingProcedures(configNodeProcedureEnv.getScheduler()); + } + } finally { + configNodeProcedureEnv.getSchedulerLock().unlock(); + } + } + + @Override + public void serialize(DataOutputStream stream) throws IOException { + stream.writeShort(ProcedureType.RECONSTRUCT_REGION_PROCEDURE.getTypeCode()); + super.serialize(stream); + ThriftCommonsSerDeUtils.serializeTConsensusGroupId(regionId, stream); + ThriftCommonsSerDeUtils.serializeTDataNodeLocation(targetDataNode, stream); + ThriftCommonsSerDeUtils.serializeTDataNodeLocation(coordinator, stream); + } + + @Override + public void deserialize(ByteBuffer byteBuffer) { + super.deserialize(byteBuffer); + try { + regionId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); + targetDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); + coordinator = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); + } catch (ThriftSerDeException e) { + LOGGER.warn( + "Error in deserialize {} (procID {}). This procedure will be ignored. It may belong to old version and cannot be used now.", + this.getClass(), + this.getProcId(), + e); + throw e; + } + } + + @Override + protected ReconstructRegionState getState(int stateId) { + return ReconstructRegionState.values()[stateId]; + } + + @Override + protected int getStateId(ReconstructRegionState reconstructRegionState) { + return reconstructRegionState.ordinal(); + } + + @Override + protected ReconstructRegionState getInitialState() { + return ReconstructRegionState.RECONSTRUCT_REGION_PREPARE; + } + + @Override + public String toString() { + return super.toString() + + ", targetDataNode=" + + targetDataNode.getDataNodeId() + + ", coordinator=" + + coordinator.getDataNodeId(); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionMigrateProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionMigrateProcedure.java index 474956a096c3..951d521784b6 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionMigrateProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionMigrateProcedure.java @@ -27,7 +27,6 @@ import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; import org.apache.iotdb.confignode.procedure.env.RegionMaintainHandler; import org.apache.iotdb.confignode.procedure.exception.ProcedureException; -import org.apache.iotdb.confignode.procedure.impl.StateMachineProcedure; import org.apache.iotdb.confignode.procedure.state.ProcedureLockState; import org.apache.iotdb.confignode.procedure.state.RegionTransitionState; import org.apache.iotdb.confignode.procedure.store.ProcedureType; @@ -42,15 +41,13 @@ import java.util.Objects; /** Region migrate procedure */ -public class RegionMigrateProcedure - extends StateMachineProcedure { +public class RegionMigrateProcedure extends RegionOperationProcedure { private static final Logger LOGGER = LoggerFactory.getLogger(RegionMigrateProcedure.class); /** Wait region migrate finished */ - private TConsensusGroupId consensusGroupId; - private TDataNodeLocation originalDataNode; + private TDataNodeLocation destDataNode; private TDataNodeLocation coordinatorForAddPeer; private TDataNodeLocation coordinatorForRemovePeer; @@ -65,8 +62,7 @@ public RegionMigrateProcedure( TDataNodeLocation destDataNode, TDataNodeLocation coordinatorForAddPeer, TDataNodeLocation coordinatorForRemovePeer) { - super(); - this.consensusGroupId = consensusGroupId; + super(consensusGroupId); this.originalDataNode = originalDataNode; this.destDataNode = destDataNode; this.coordinatorForAddPeer = coordinatorForAddPeer; @@ -75,7 +71,7 @@ public RegionMigrateProcedure( @Override protected Flow executeFromState(ConfigNodeProcedureEnv env, RegionTransitionState state) { - if (consensusGroupId == null) { + if (regionId == null) { return Flow.NO_MORE_STATE; } RegionMaintainHandler handler = env.getRegionMaintainHandler(); @@ -85,22 +81,22 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RegionTransitionStat LOGGER.info( "[pid{}][MigrateRegion] started, {} will be migrated from DataNode {} to {}.", getProcId(), - consensusGroupId, + regionId, handler.simplifiedLocation(originalDataNode), handler.simplifiedLocation(destDataNode)); setNextState(RegionTransitionState.ADD_REGION_PEER); break; case ADD_REGION_PEER: addChildProcedure( - new AddRegionPeerProcedure(consensusGroupId, coordinatorForAddPeer, destDataNode)); + new AddRegionPeerProcedure(regionId, coordinatorForAddPeer, destDataNode)); setNextState(RegionTransitionState.CHECK_ADD_REGION_PEER); break; case CHECK_ADD_REGION_PEER: if (!env.getConfigManager() .getPartitionManager() - .isDataNodeContainsRegion(destDataNode.getDataNodeId(), consensusGroupId)) { + .isDataNodeContainsRegion(destDataNode.getDataNodeId(), regionId)) { LOGGER.warn( - "[pid{}][MigrateRegion] sub-procedure AddRegionPeerProcedure fail, RegionMigrateProcedure will not continue", + "[pid{}][MigrateRegion] sub-procedure AddRegionPeerProcedure failed, RegionMigrateProcedure will not continue", getProcId()); return Flow.NO_MORE_STATE; } @@ -108,15 +104,14 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RegionTransitionStat break; case REMOVE_REGION_PEER: addChildProcedure( - new RemoveRegionPeerProcedure( - consensusGroupId, coordinatorForRemovePeer, originalDataNode)); + new RemoveRegionPeerProcedure(regionId, coordinatorForRemovePeer, originalDataNode)); setNextState(RegionTransitionState.CHECK_REMOVE_REGION_PEER); break; case CHECK_REMOVE_REGION_PEER: String cleanHint = ""; if (env.getConfigManager() .getPartitionManager() - .isDataNodeContainsRegion(originalDataNode.getDataNodeId(), consensusGroupId)) { + .isDataNodeContainsRegion(originalDataNode.getDataNodeId(), regionId)) { cleanHint = "but you may need to restart the related DataNode to make sure everything is cleaned up. "; } @@ -124,7 +119,7 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RegionTransitionStat "[pid{}][MigrateRegion] success,{} {} has been migrated from DataNode {} to {}. Procedure took {} (started at {}).", getProcId(), cleanHint, - consensusGroupId, + regionId, handler.simplifiedLocation(originalDataNode), handler.simplifiedLocation(destDataNode), CommonDateTimeUtils.convertMillisecondToDurationStr( @@ -200,7 +195,7 @@ public void serialize(DataOutputStream stream) throws IOException { super.serialize(stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(originalDataNode, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(destDataNode, stream); - ThriftCommonsSerDeUtils.serializeTConsensusGroupId(consensusGroupId, stream); + ThriftCommonsSerDeUtils.serializeTConsensusGroupId(regionId, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(coordinatorForAddPeer, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(coordinatorForRemovePeer, stream); } @@ -211,7 +206,7 @@ public void deserialize(ByteBuffer byteBuffer) { try { originalDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); destDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); - consensusGroupId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); + regionId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); coordinatorForAddPeer = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); coordinatorForRemovePeer = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); } catch (ThriftSerDeException e) { @@ -232,18 +227,14 @@ public boolean equals(Object that) { && thatProc.getState() == this.getState() && thatProc.originalDataNode.equals(this.originalDataNode) && thatProc.destDataNode.equals(this.destDataNode) - && thatProc.consensusGroupId.equals(this.consensusGroupId); + && thatProc.regionId.equals(this.regionId); } return false; } @Override public int hashCode() { - return Objects.hash(this.originalDataNode, this.destDataNode, this.consensusGroupId); - } - - public TConsensusGroupId getConsensusGroupId() { - return consensusGroupId; + return Objects.hash(this.originalDataNode, this.destDataNode, this.regionId); } public TDataNodeLocation getDestDataNode() { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionOperationProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionOperationProcedure.java new file mode 100644 index 000000000000..ad0cb38ac82d --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RegionOperationProcedure.java @@ -0,0 +1,48 @@ +/* + * 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.procedure.impl.region; + +import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; +import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; +import org.apache.iotdb.confignode.procedure.impl.StateMachineProcedure; + +public abstract class RegionOperationProcedure + extends StateMachineProcedure { + TConsensusGroupId regionId; + + public RegionOperationProcedure() {} + + public RegionOperationProcedure(TConsensusGroupId regionId) { + this.regionId = regionId; + } + + public void setRegionId(TConsensusGroupId regionId) { + this.regionId = regionId; + } + + public TConsensusGroupId getRegionId() { + return regionId; + } + + @Override + public String toString() { + return super.toString() + ", regionId=" + regionId; + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RemoveRegionPeerProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RemoveRegionPeerProcedure.java index 472978c9b0d4..64905361250f 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RemoveRegionPeerProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/region/RemoveRegionPeerProcedure.java @@ -32,7 +32,6 @@ import org.apache.iotdb.confignode.procedure.exception.ProcedureException; import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; import org.apache.iotdb.confignode.procedure.exception.ProcedureYieldException; -import org.apache.iotdb.confignode.procedure.impl.StateMachineProcedure; import org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState; import org.apache.iotdb.confignode.procedure.store.ProcedureType; import org.apache.iotdb.db.utils.DateTimeUtils; @@ -52,10 +51,8 @@ import static org.apache.iotdb.confignode.procedure.state.RemoveRegionPeerState.REMOVE_REGION_PEER; import static org.apache.iotdb.rpc.TSStatusCode.SUCCESS_STATUS; -public class RemoveRegionPeerProcedure - extends StateMachineProcedure { +public class RemoveRegionPeerProcedure extends RegionOperationProcedure { private static final Logger LOGGER = LoggerFactory.getLogger(RemoveRegionPeerProcedure.class); - private TConsensusGroupId consensusGroupId; private TDataNodeLocation coordinator; private TDataNodeLocation targetDataNode; @@ -67,7 +64,7 @@ public RemoveRegionPeerProcedure( TConsensusGroupId consensusGroupId, TDataNodeLocation coordinator, TDataNodeLocation targetDataNode) { - this.consensusGroupId = consensusGroupId; + super(consensusGroupId); this.coordinator = coordinator; this.targetDataNode = targetDataNode; } @@ -77,16 +74,16 @@ private void handleTransferLeader(RegionMaintainHandler handler) LOGGER.info( "[pid{}][RemoveRegion] started, region {} will be removed from DataNode {}.", getProcId(), - consensusGroupId.getId(), + regionId.getId(), targetDataNode.getDataNodeId()); - handler.forceUpdateRegionCache(consensusGroupId, targetDataNode, RegionStatus.Removing); - handler.transferRegionLeader(consensusGroupId, targetDataNode, coordinator); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Removing); + handler.transferRegionLeader(regionId, targetDataNode, coordinator); } @Override protected Flow executeFromState(ConfigNodeProcedureEnv env, RemoveRegionPeerState state) throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException { - if (consensusGroupId == null) { + if (regionId == null) { return Flow.NO_MORE_STATE; } TSStatus tsStatus; @@ -99,18 +96,18 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RemoveRegionPeerStat setNextState(REMOVE_REGION_PEER); break; case REMOVE_REGION_PEER: - handler.forceUpdateRegionCache(consensusGroupId, targetDataNode, RegionStatus.Removing); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Removing); tsStatus = handler.submitRemoveRegionPeerTask( - this.getProcId(), targetDataNode, consensusGroupId, coordinator); + this.getProcId(), targetDataNode, regionId, coordinator); setKillPoint(state); if (tsStatus.getCode() != SUCCESS_STATUS.getStatusCode()) { LOGGER.warn( "[pid{}][RemoveRegion] {} task submitted failed, ConfigNode believe current peer list of {} is {}. Procedure will continue. You should manually clear peer list.", getProcId(), state, - consensusGroupId, - handler.getRegionReplicaSetString(consensusGroupId)); + regionId, + handler.getRegionReplicaSetString(regionId)); setNextState(DELETE_OLD_REGION_PEER); return Flow.HAS_MORE_STATE; } @@ -121,24 +118,23 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RemoveRegionPeerStat "[pid{}][RemoveRegion] {} executed failed, ConfigNode believe current peer list of {} is {}. Procedure will continue. You should manually clear peer list.", getProcId(), state, - consensusGroupId, - handler.getRegionReplicaSetString(consensusGroupId)); + regionId, + handler.getRegionReplicaSetString(regionId)); setNextState(DELETE_OLD_REGION_PEER); return Flow.HAS_MORE_STATE; } setNextState(DELETE_OLD_REGION_PEER); break; case DELETE_OLD_REGION_PEER: - handler.forceUpdateRegionCache(consensusGroupId, targetDataNode, RegionStatus.Removing); + handler.forceUpdateRegionCache(regionId, targetDataNode, RegionStatus.Removing); tsStatus = - handler.submitDeleteOldRegionPeerTask( - this.getProcId(), targetDataNode, consensusGroupId); + handler.submitDeleteOldRegionPeerTask(this.getProcId(), targetDataNode, regionId); setKillPoint(state); if (tsStatus.getCode() != SUCCESS_STATUS.getStatusCode()) { LOGGER.warn( "[pid{}][RemoveRegion] DELETE_OLD_REGION_PEER task submitted failed, procedure will continue. You should manually delete region file. {}", getProcId(), - consensusGroupId); + regionId); setNextState(REMOVE_REGION_LOCATION_CACHE); return Flow.HAS_MORE_STATE; } @@ -148,20 +144,20 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RemoveRegionPeerStat LOGGER.warn( "[pid{}][RemoveRegion] DELETE_OLD_REGION_PEER executed failed, procedure will continue. You should manually delete region file. {}", getProcId(), - consensusGroupId); + regionId); setNextState(REMOVE_REGION_LOCATION_CACHE); return Flow.HAS_MORE_STATE; } setNextState(REMOVE_REGION_LOCATION_CACHE); break; case REMOVE_REGION_LOCATION_CACHE: - handler.removeRegionLocation(consensusGroupId, targetDataNode); + handler.removeRegionLocation(regionId, targetDataNode); setKillPoint(state); LOGGER.info("RemoveRegionPeer state {} success", state); LOGGER.info( "[pid{}][RemoveRegion] success, region {} has been removed from DataNode {}. Procedure took {} (started at {})", getProcId(), - consensusGroupId.getId(), + regionId.getId(), targetDataNode.getDataNodeId(), CommonDateTimeUtils.convertMillisecondToDurationStr( System.currentTimeMillis() - getSubmittedTime()), @@ -201,7 +197,7 @@ protected RemoveRegionPeerState getInitialState() { public void serialize(DataOutputStream stream) throws IOException { stream.writeShort(ProcedureType.REMOVE_REGION_PEER_PROCEDURE.getTypeCode()); super.serialize(stream); - ThriftCommonsSerDeUtils.serializeTConsensusGroupId(consensusGroupId, stream); + ThriftCommonsSerDeUtils.serializeTConsensusGroupId(regionId, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(targetDataNode, stream); ThriftCommonsSerDeUtils.serializeTDataNodeLocation(coordinator, stream); } @@ -210,7 +206,7 @@ public void serialize(DataOutputStream stream) throws IOException { public void deserialize(ByteBuffer byteBuffer) { super.deserialize(byteBuffer); try { - consensusGroupId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); + regionId = ThriftCommonsSerDeUtils.deserializeTConsensusGroupId(byteBuffer); targetDataNode = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); coordinator = ThriftCommonsSerDeUtils.deserializeTDataNodeLocation(byteBuffer); } catch (ThriftSerDeException e) { @@ -218,10 +214,6 @@ public void deserialize(ByteBuffer byteBuffer) { } } - public TConsensusGroupId getConsensusGroupId() { - return consensusGroupId; - } - public TDataNodeLocation getCoordinator() { return coordinator; } @@ -236,13 +228,13 @@ public boolean equals(Object obj) { return false; } RemoveRegionPeerProcedure procedure = (RemoveRegionPeerProcedure) obj; - return this.consensusGroupId.equals(procedure.consensusGroupId) + return this.regionId.equals(procedure.regionId) && this.targetDataNode.equals(procedure.targetDataNode) && this.coordinator.equals(procedure.coordinator); } @Override public int hashCode() { - return Objects.hash(consensusGroupId, targetDataNode, coordinator); + return Objects.hash(regionId, targetDataNode, coordinator); } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/ReconstructRegionState.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/ReconstructRegionState.java new file mode 100644 index 000000000000..ef7abc5329cc --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/ReconstructRegionState.java @@ -0,0 +1,28 @@ +/* + * 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.procedure.state; + +public enum ReconstructRegionState { + RECONSTRUCT_REGION_PREPARE, + REMOVE_REGION_PEER, + CHECK_REMOVE_REGION_PEER, + ADD_REGION_PEER, + CHECK_ADD_REGION_PEER, +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java index 42ef4a1b8069..aaeb85fa076e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java @@ -40,6 +40,7 @@ import org.apache.iotdb.confignode.procedure.impl.pipe.task.StopPipeProcedureV2; import org.apache.iotdb.confignode.procedure.impl.region.AddRegionPeerProcedure; import org.apache.iotdb.confignode.procedure.impl.region.CreateRegionGroupsProcedure; +import org.apache.iotdb.confignode.procedure.impl.region.ReconstructRegionProcedure; import org.apache.iotdb.confignode.procedure.impl.region.RegionMigrateProcedure; import org.apache.iotdb.confignode.procedure.impl.region.RemoveRegionPeerProcedure; import org.apache.iotdb.confignode.procedure.impl.schema.AlterLogicalViewProcedure; @@ -124,6 +125,8 @@ public Procedure create(ByteBuffer buffer) throws IOException { case CREATE_REGION_GROUPS: procedure = new CreateRegionGroupsProcedure(); break; + case RECONSTRUCT_REGION_PROCEDURE: + procedure = new ReconstructRegionProcedure(); case DELETE_TIMESERIES_PROCEDURE: procedure = new DeleteTimeSeriesProcedure(false); break; @@ -341,6 +344,8 @@ public static ProcedureType getProcedureType(final Procedure procedure) { return ProcedureType.CREATE_REGION_GROUPS; } else if (procedure instanceof DeleteTimeSeriesProcedure) { return ProcedureType.DELETE_TIMESERIES_PROCEDURE; + } else if (procedure instanceof ReconstructRegionProcedure) { + return ProcedureType.RECONSTRUCT_REGION_PROCEDURE; } else if (procedure instanceof CreateTriggerProcedure) { return ProcedureType.CREATE_TRIGGER_PROCEDURE; } else if (procedure instanceof DropTriggerProcedure) { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java index 9928a214b757..8cca96bb74e7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java @@ -37,10 +37,11 @@ public enum ProcedureType { DELETE_DATABASE_PROCEDURE((short) 200), REGION_MIGRATE_PROCEDURE((short) 201), CREATE_REGION_GROUPS((short) 202), - @TestOnly - CREATE_MANY_DATABASES_PROCEDURE((short) 203), + RECONSTRUCT_REGION_PROCEDURE((short) 203), ADD_REGION_PEER_PROCEDURE((short) 204), REMOVE_REGION_PEER_PROCEDURE((short) 205), + @TestOnly + CREATE_MANY_DATABASES_PROCEDURE((short) 250), /** Timeseries */ DELETE_TIMESERIES_PROCEDURE((short) 300), diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java index ecfe6455d4b4..da176c4562c2 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java @@ -136,6 +136,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDropPipeReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTopicReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TFetchTableResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllPipeInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllSubscriptionInfoResp; @@ -167,7 +168,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferResp; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp; import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionReq; @@ -1231,6 +1234,21 @@ public TSStatus migrateRegion(TMigrateRegionReq req) { return configManager.migrateRegion(req); } + @Override + public TSStatus reconstructRegion(TReconstructRegionReq req) { + return configManager.reconstructRegion(req); + } + + @Override + public TSStatus extendRegion(TExtendRegionReq req) throws TException { + return configManager.extendRegion(req); + } + + @Override + public TSStatus removeRegion(TRemoveRegionReq req) throws TException { + return configManager.removeRegion(req); + } + @Override public TSStatus createCQ(TCreateCQReq req) { return configManager.createCQ(req); 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 a3ff327e9ef5..26403e068dc1 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 @@ -99,6 +99,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDropPipeReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTopicReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TFetchTableResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllPipeInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllSubscriptionInfoResp; @@ -130,7 +131,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferResp; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementReq; import org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp; import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionReq; @@ -1191,6 +1194,24 @@ public TSStatus migrateRegion(TMigrateRegionReq req) throws TException { () -> client.migrateRegion(req), status -> !updateConfigNodeLeader(status)); } + @Override + public TSStatus reconstructRegion(TReconstructRegionReq req) throws TException { + return executeRemoteCallWithRetry( + () -> client.reconstructRegion(req), status -> !updateConfigNodeLeader(status)); + } + + @Override + public TSStatus extendRegion(TExtendRegionReq req) throws TException { + return executeRemoteCallWithRetry( + () -> client.extendRegion(req), status -> !updateConfigNodeLeader(status)); + } + + @Override + public TSStatus removeRegion(TRemoveRegionReq req) throws TException { + return executeRemoteCallWithRetry( + () -> client.removeRegion(req), status -> !updateConfigNodeLeader(status)); + } + @Override public TSStatus createCQ(TCreateCQReq req) throws TException { return executeRemoteCallWithRetry( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java index a1ee08d84e45..33ae1fda1854 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TreeConfigTaskVisitor.java @@ -40,7 +40,6 @@ 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.MigrateRegionTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.SetTTLTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowAINodesTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowClusterDetailsTask; @@ -60,6 +59,10 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.model.CreateModelTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.model.DropModelTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.model.ShowModelsTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.ExtendRegionTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.MigrateRegionTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.ReconstructRegionTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region.RemoveRegionTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.AlterSchemaTemplateTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.CreateSchemaTemplateTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.DeactivateSchemaTemplateTask; @@ -114,7 +117,6 @@ 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.MigrateRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement; @@ -141,6 +143,10 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ExtendRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ReconstructRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.RemoveRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; @@ -628,6 +634,24 @@ public IConfigTask visitMigrateRegion( return new MigrateRegionTask(migrateRegionStatement); } + @Override + public IConfigTask visitReconstructRegion( + ReconstructRegionStatement reconstructRegionStatement, MPPQueryContext context) { + return new ReconstructRegionTask(reconstructRegionStatement); + } + + @Override + public IConfigTask visitExtendRegion( + ExtendRegionStatement extendRegionStatement, MPPQueryContext context) { + return new ExtendRegionTask(extendRegionStatement); + } + + @Override + public IConfigTask visitRemoveRegion( + RemoveRegionStatement removeRegionStatement, MPPQueryContext context) { + return new RemoveRegionTask(removeRegionStatement); + } + @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 4a14c71a3d37..50ff49dd54f3 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 @@ -95,6 +95,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TDropPipeReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTopicReq; import org.apache.iotdb.confignode.rpc.thrift.TDropTriggerReq; +import org.apache.iotdb.confignode.rpc.thrift.TExtendRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TFetchTableResp; import org.apache.iotdb.confignode.rpc.thrift.TGetAllPipeInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TGetDatabaseReq; @@ -111,7 +112,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TMigrateRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferReq; import org.apache.iotdb.confignode.rpc.thrift.TPipeConfigTransferResp; +import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TRegionInfo; +import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TShowAINodesResp; import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp; import org.apache.iotdb.confignode.rpc.thrift.TShowClusterResp; @@ -215,7 +218,6 @@ 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.MigrateRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement; @@ -230,6 +232,10 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ExtendRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ReconstructRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.RemoveRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; @@ -2759,6 +2765,73 @@ public SettableFuture migrateRegion( return future; } + @Override + public SettableFuture reconstructRegion( + ReconstructRegionStatement reconstructRegionStatement) { + final SettableFuture future = SettableFuture.create(); + try (ConfigNodeClient configNodeClient = + CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { + final TReconstructRegionReq req = + new TReconstructRegionReq( + reconstructRegionStatement.getRegionIds(), + reconstructRegionStatement.getDataNodeId()); + final TSStatus status = configNodeClient.reconstructRegion(req); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + future.setException(new IoTDBException(status.message, status.code)); + return future; + } else { + future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS)); + } + } catch (Exception e) { + future.setException(e); + } + return future; + } + + @Override + public SettableFuture extendRegion( + ExtendRegionStatement extendRegionStatement) { + final SettableFuture future = SettableFuture.create(); + try (ConfigNodeClient configNodeClient = + CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { + final TExtendRegionReq req = + new TExtendRegionReq( + extendRegionStatement.getRegionId(), extendRegionStatement.getDataNodeId()); + final TSStatus status = configNodeClient.extendRegion(req); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + future.setException(new IoTDBException(status.message, status.code)); + return future; + } else { + future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS)); + } + } catch (Exception e) { + future.setException(e); + } + return future; + } + + @Override + public SettableFuture removeRegion( + RemoveRegionStatement removeRegionStatement) { + final SettableFuture future = SettableFuture.create(); + try (ConfigNodeClient configNodeClient = + CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { + final TRemoveRegionReq req = + new TRemoveRegionReq( + removeRegionStatement.getRegionId(), removeRegionStatement.getDataNodeId()); + final TSStatus status = configNodeClient.removeRegion(req); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + future.setException(new IoTDBException(status.message, status.code)); + return future; + } else { + future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS)); + } + } catch (Exception e) { + future.setException(e); + } + return future; + } + @Override public SettableFuture createContinuousQuery( final CreateContinuousQueryStatement createContinuousQueryStatement, 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 179d24550376..4fec676f0bf8 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 @@ -51,7 +51,6 @@ 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.MigrateRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement; @@ -66,6 +65,10 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ExtendRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ReconstructRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.RemoveRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; @@ -249,6 +252,13 @@ SettableFuture countTimeSlotList( SettableFuture migrateRegion(MigrateRegionStatement migrateRegionStatement); + SettableFuture reconstructRegion( + ReconstructRegionStatement reconstructRegionStatement); + + SettableFuture extendRegion(ExtendRegionStatement extendRegionStatement); + + SettableFuture removeRegion(RemoveRegionStatement removeRegionStatement); + SettableFuture createContinuousQuery( CreateContinuousQueryStatement createContinuousQueryStatement, MPPQueryContext context); 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 new file mode 100644 index 000000000000..00dafd9d1549 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ExtendRegionTask.java @@ -0,0 +1,42 @@ +/* + * 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.region; + +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.region.ExtendRegionStatement; + +import com.google.common.util.concurrent.ListenableFuture; + +public class ExtendRegionTask implements IConfigTask { + + protected final ExtendRegionStatement statement; + + public ExtendRegionTask(ExtendRegionStatement statement) { + this.statement = statement; + } + + @Override + public ListenableFuture execute(IConfigTaskExecutor configTaskExecutor) + throws InterruptedException { + return configTaskExecutor.extendRegion(statement); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/MigrateRegionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/MigrateRegionTask.java similarity index 94% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/MigrateRegionTask.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/MigrateRegionTask.java index e85454613bef..fd22585aa8cf 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/MigrateRegionTask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/MigrateRegionTask.java @@ -17,12 +17,12 @@ * under the License. */ -package org.apache.iotdb.db.queryengine.plan.execution.config.metadata; +package org.apache.iotdb.db.queryengine.plan.execution.config.metadata.region; 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.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; import com.google.common.util.concurrent.ListenableFuture; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ReconstructRegionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ReconstructRegionTask.java new file mode 100644 index 000000000000..f5276ed64e7c --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/ReconstructRegionTask.java @@ -0,0 +1,42 @@ +/* + * 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.region; + +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.region.ReconstructRegionStatement; + +import com.google.common.util.concurrent.ListenableFuture; + +public class ReconstructRegionTask implements IConfigTask { + + protected final ReconstructRegionStatement reconstructRegionStatement; + + public ReconstructRegionTask(ReconstructRegionStatement reconstructRegionStatement) { + this.reconstructRegionStatement = reconstructRegionStatement; + } + + @Override + public ListenableFuture execute(IConfigTaskExecutor configTaskExecutor) + throws InterruptedException { + return configTaskExecutor.reconstructRegion(reconstructRegionStatement); + } +} 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 new file mode 100644 index 000000000000..26ecea097f74 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/region/RemoveRegionTask.java @@ -0,0 +1,42 @@ +/* + * 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.region; + +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.region.RemoveRegionStatement; + +import com.google.common.util.concurrent.ListenableFuture; + +public class RemoveRegionTask implements IConfigTask { + + protected final RemoveRegionStatement statement; + + public RemoveRegionTask(RemoveRegionStatement statement) { + this.statement = statement; + } + + @Override + public ListenableFuture execute(IConfigTaskExecutor configTaskExecutor) + throws InterruptedException { + return configTaskExecutor.removeRegion(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 9b45b9b03d15..2948f946925f 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,7 +148,6 @@ 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.MigrateRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement; @@ -180,6 +179,10 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ExtendRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ReconstructRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.RemoveRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; @@ -227,6 +230,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.io.BaseEncoding; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.commons.lang3.StringUtils; import org.apache.tsfile.common.conf.TSFileDescriptor; @@ -4177,6 +4181,29 @@ public Statement visitMigrateRegion(IoTDBSqlParser.MigrateRegionContext ctx) { Integer.parseInt(ctx.toId.getText())); } + @Override + public Statement visitReconstructRegion(IoTDBSqlParser.ReconstructRegionContext ctx) { + int dataNodeId = Integer.parseInt(ctx.targetDataNodeId.getText()); + List regionIds = + ctx.regionIds.stream() + .map(Token::getText) + .map(Integer::parseInt) + .collect(Collectors.toList()); + return new ReconstructRegionStatement(dataNodeId, regionIds); + } + + @Override + public Statement visitExtendRegion(IoTDBSqlParser.ExtendRegionContext ctx) { + return new ExtendRegionStatement( + Integer.parseInt(ctx.regionId.getText()), 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())); + } + @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 d15677de60b7..7f4181be8b35 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,7 +55,6 @@ 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.MigrateRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement; @@ -87,6 +86,10 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ExtendRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.MigrateRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.ReconstructRegionStatement; +import org.apache.iotdb.db.queryengine.plan.statement.metadata.region.RemoveRegionStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; @@ -577,6 +580,19 @@ public R visitMigrateRegion(MigrateRegionStatement migrateRegionStatement, C con return visitStatement(migrateRegionStatement, context); } + public R visitReconstructRegion( + ReconstructRegionStatement reconstructRegionStatement, C context) { + return visitStatement(reconstructRegionStatement, context); + } + + public R visitExtendRegion(ExtendRegionStatement extendRegionStatement, C context) { + return visitStatement(extendRegionStatement, context); + } + + public R visitRemoveRegion(RemoveRegionStatement removeRegionStatement, C context) { + return visitStatement(removeRegionStatement, 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/region/ExtendRegionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java new file mode 100644 index 000000000000..581ba6bf10fe --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ExtendRegionStatement.java @@ -0,0 +1,64 @@ +/* + * 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.region; + +import org.apache.iotdb.commons.path.PartialPath; +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 java.util.Collections; +import java.util.List; + +public class ExtendRegionStatement extends Statement implements IConfigStatement { + + private final int regionId; + private final int dataNodeId; + + public ExtendRegionStatement(int regionId, int dataNodeId) { + super(); + this.regionId = regionId; + this.dataNodeId = dataNodeId; + } + + public int getRegionId() { + return regionId; + } + + public int getDataNodeId() { + return dataNodeId; + } + + @Override + public R accept(StatementVisitor visitor, C context) { + return visitor.visitExtendRegion(this, context); + } + + @Override + public QueryType getQueryType() { + return QueryType.WRITE; + } + + @Override + public List getPaths() { + return Collections.emptyList(); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/MigrateRegionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/MigrateRegionStatement.java similarity index 96% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/MigrateRegionStatement.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/MigrateRegionStatement.java index 6127dbc2bfb2..616357f53795 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/MigrateRegionStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/MigrateRegionStatement.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.iotdb.db.queryengine.plan.statement.metadata; +package org.apache.iotdb.db.queryengine.plan.statement.metadata.region; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.queryengine.plan.analyze.QueryType; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ReconstructRegionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ReconstructRegionStatement.java new file mode 100644 index 000000000000..cd22e61ad7f7 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/ReconstructRegionStatement.java @@ -0,0 +1,62 @@ +/* + * 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.region; + +import org.apache.iotdb.commons.path.PartialPath; +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 java.util.Collections; +import java.util.List; + +public class ReconstructRegionStatement extends Statement implements IConfigStatement { + final int dataNodeId; + final List regionIds; + + public ReconstructRegionStatement(int dataNodeId, List regionIds) { + this.dataNodeId = dataNodeId; + this.regionIds = regionIds; + } + + public int getDataNodeId() { + return dataNodeId; + } + + public List getRegionIds() { + return regionIds; + } + + @Override + public R accept(StatementVisitor visitor, C context) { + return visitor.visitReconstructRegion(this, context); + } + + @Override + public QueryType getQueryType() { + return QueryType.WRITE; + } + + @Override + public List getPaths() { + return Collections.emptyList(); + } +} 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 new file mode 100644 index 000000000000..fae5bebad70e --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/region/RemoveRegionStatement.java @@ -0,0 +1,64 @@ +/* + * 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.region; + +import org.apache.iotdb.commons.path.PartialPath; +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 java.util.Collections; +import java.util.List; + +public class RemoveRegionStatement extends Statement implements IConfigStatement { + + private final int regionId; + private final int dataNodeId; + + public RemoveRegionStatement(int regionId, int dataNodeId) { + super(); + this.regionId = regionId; + this.dataNodeId = dataNodeId; + } + + public int getRegionId() { + return regionId; + } + + public int getDataNodeId() { + return dataNodeId; + } + + @Override + public R accept(StatementVisitor visitor, C context) { + return visitor.visitRemoveRegion(this, context); + } + + @Override + public QueryType getQueryType() { + return QueryType.WRITE; + } + + @Override + public List getPaths() { + return Collections.emptyList(); + } +} diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift index f2e6c1400916..a6a7b4bedb8b 100644 --- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift +++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift @@ -312,6 +312,21 @@ struct TMigrateRegionReq { 3: required i32 toId } +struct TReconstructRegionReq { + 1: required list regionIds + 2: required i32 dataNodeId +} + +struct TExtendRegionReq { + 1: required i32 regionId + 2: required i32 dataNodeId +} + +struct TRemoveRegionReq { + 1: required i32 regionId + 2: required i32 dataNodeId +} + // Authorize struct TAuthorizerReq { 1: required i32 authorType @@ -1547,6 +1562,12 @@ service IConfigNodeRPCService { /** Migrate a region replica from one dataNode to another */ common.TSStatus migrateRegion(TMigrateRegionReq req) + common.TSStatus reconstructRegion(TReconstructRegionReq req) + + common.TSStatus extendRegion(TExtendRegionReq req) + + common.TSStatus removeRegion(TRemoveRegionReq req) + /** Kill query */ common.TSStatus killQuery(string queryId, i32 dataNodeId)