This is an automated email from the ASF dual-hosted git repository.
CRZbulabula pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 87a6d198a90 Allow removing regions from read-only DataNodes (#18670)
87a6d198a90 is described below
commit 87a6d198a901f46630a3455f59b264fc9368ca08
Author: Yongzao <[email protected]>
AuthorDate: Fri Sep 18 13:57:00 2026 +0800
Allow removing regions from read-only DataNodes (#18670)
---
.../iotdb/confignode/manager/ProcedureManager.java | 28 +++++++++++++++-------
.../ProcedureManagerReconstructRegionTest.java | 23 +++++++++++++++++-
2 files changed, 41 insertions(+), 10 deletions(-)
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 ac1a53539f6..28b54fa61d5 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
@@ -861,7 +861,8 @@ public class ProcedureManager {
new Pair<>("Original DataNode", originalDataNode),
new Pair<>("Destination DataNode", destDataNode),
new Pair<>("Coordinator for add peer",
coordinatorForAddPeer)),
- migrateRegionReq.getModel()))
+ migrateRegionReq.getModel(),
+ NodeStatus.Running))
!= null) {
// do nothing
} else if (configManager
@@ -905,7 +906,8 @@ public class ProcedureManager {
Arrays.asList(
new Pair<>("Target DataNode", targetDataNode),
new Pair<>("Coordinator", coordinator)),
- req.getModel());
+ req.getModel(),
+ NodeStatus.Running);
if (configManager
.getPartitionManager()
@@ -946,7 +948,8 @@ public class ProcedureManager {
Arrays.asList(
new Pair<>("Target DataNode", targetDataNode),
new Pair<>("Coordinator", coordinator)),
- req.getModel());
+ req.getModel(),
+ NodeStatus.Running);
if (configManager
.getPartitionManager()
.getAllReplicaSets(targetDataNode.getDataNodeId())
@@ -977,7 +980,9 @@ public class ProcedureManager {
regionId,
targetDataNode,
Arrays.asList(new Pair<>("Coordinator", coordinator)),
- req.getModel());
+ req.getModel(),
+ NodeStatus.Running,
+ NodeStatus.ReadOnly);
if (configManager
.getPartitionManager()
@@ -1011,15 +1016,17 @@ public class ProcedureManager {
* removing
*
* @param regionId region group id, also called consensus group id
- * @param targetDataNode DataNode should in Running status
+ * @param targetDataNode DataNode participating in the region operation
* @param relatedDataNodes Pair<Identity, Node Location>
+ * @param targetDataNodeAllowedStatuses statuses accepted for the target
DataNode
* @return The reason if check failed, or null if check pass
*/
private String regionOperationCommonCheck(
TConsensusGroupId regionId,
TDataNodeLocation targetDataNode,
List<Pair<String, TDataNodeLocation>> relatedDataNodes,
- Model model) {
+ Model model,
+ NodeStatus... targetDataNodeAllowedStatuses) {
String failMessage;
ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf();
@@ -1036,13 +1043,16 @@ public class ProcedureManager {
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()
+ && !configManager
+ .getNodeManager()
+ .filterDataNodeThroughStatus(targetDataNodeAllowedStatuses)
+ .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
+ // The accepted statuses depend on the region operation. For example,
REMOVE REGION also
+ // accepts a ReadOnly target because the target replica is being removed.
failMessage =
String.format(
"Target DataNode %s is not in Running status.",
targetDataNode.getDataNodeId());
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ProcedureManagerReconstructRegionTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ProcedureManagerReconstructRegionTest.java
index a21a5da7083..4e2b58daa63 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ProcedureManagerReconstructRegionTest.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ProcedureManagerReconstructRegionTest.java
@@ -36,6 +36,7 @@ import
org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
import org.apache.iotdb.confignode.procedure.env.RegionMaintainHandler;
import
org.apache.iotdb.confignode.procedure.impl.region.ReconstructRegionProcedure;
import org.apache.iotdb.confignode.rpc.thrift.TReconstructRegionReq;
+import org.apache.iotdb.confignode.rpc.thrift.TRemoveRegionReq;
import org.apache.iotdb.rpc.TSStatusCode;
import org.junit.Before;
@@ -71,6 +72,7 @@ public class ProcedureManagerReconstructRegionTest {
private ProcedureManager manager;
private ProcedureExecutor<ConfigNodeProcedureEnv> executor;
+ private NodeManager nodeManager;
private PartitionManager partitionManager;
private final ConcurrentHashMap<Long, Procedure<ConfigNodeProcedureEnv>>
procedures =
new ConcurrentHashMap<>();
@@ -78,7 +80,7 @@ public class ProcedureManagerReconstructRegionTest {
@Before
public void setUp() throws Exception {
ConfigManager configManager = mock(ConfigManager.class);
- NodeManager nodeManager = mock(NodeManager.class);
+ nodeManager = mock(NodeManager.class);
partitionManager = mock(PartitionManager.class);
ConfigNodeProcedureEnv env = mock(ConfigNodeProcedureEnv.class);
RegionMaintainHandler handler = mock(RegionMaintainHandler.class);
@@ -90,10 +92,16 @@ public class ProcedureManagerReconstructRegionTest {
.thenReturn(new TDataNodeConfiguration().setLocation(target));
when(nodeManager.filterDataNodeThroughStatus(NodeStatus.Running))
.thenReturn(Collections.singletonList(new
TDataNodeConfiguration().setLocation(target)));
+ when(nodeManager.filterDataNodeThroughStatus(NodeStatus.Running,
NodeStatus.ReadOnly))
+ .thenReturn(Collections.singletonList(new
TDataNodeConfiguration().setLocation(target)));
when(partitionManager.findTConsensusGroupIdByRegionId(12)).thenReturn(Optional.of(firstRegion));
when(partitionManager.findTConsensusGroupIdByRegionId(14))
.thenReturn(Optional.of(secondRegion));
when(partitionManager.findTConsensusGroupIdByRegionId(99)).thenReturn(Optional.empty());
+ when(partitionManager.generateTConsensusGroupIdByRegionId(12))
+ .thenReturn(Optional.of(firstRegion));
+ when(partitionManager.generateTConsensusGroupIdByRegionId(14))
+ .thenReturn(Optional.of(secondRegion));
when(partitionManager.getRegionDatabase(any(TConsensusGroupId.class))).thenReturn("root.sg");
Map<TConsensusGroupId, TRegionReplicaSet> replicaSets = new HashMap<>();
@@ -166,4 +174,17 @@ public class ProcedureManagerReconstructRegionTest {
assertTrue(status.getMessage().contains("in progress"));
verify(executor, times(0)).submitProcedure(any());
}
+
+ @Test
+ public void testRemoveRegionAllowsReadOnlyTargetDataNode() {
+ procedures.clear();
+ when(nodeManager.filterDataNodeThroughStatus(NodeStatus.Running))
+ .thenReturn(
+ Collections.singletonList(new
TDataNodeConfiguration().setLocation(coordinator)));
+ TRemoveRegionReq request = new
TRemoveRegionReq(Collections.singletonList(12), 7, Model.TREE);
+
+ assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
manager.removeRegions(request).getCode());
+ verify(executor, times(1)).submitProcedure(any());
+ }
}