From 99a004d63c9d76503c0b87e681f7d88a0af7a683 Mon Sep 17 00:00:00 2001 From: Di Wang Date: Tue, 20 Oct 2026 22:03:28 +0800 Subject: [PATCH] Restore DataNode removal cleanup after child procedure failures Allow STOP_DATA_NODE rollback cleanup under the commit-point guard. Preserve execution retries and verify transient cleanup failures stay retryable. --- .../impl/node/RemoveDataNodesProcedure.java | 25 +++++++++---------- .../node/RemoveDataNodePersistenceTest.java | 2 ++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodesProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodesProcedure.java index 06986a724587..212bc1dca889 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodesProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodesProcedure.java @@ -158,19 +158,16 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, RemoveDataNodeState return Flow.NO_MORE_STATE; } } catch (Exception e) { - if (isRollbackSupported(state)) { - setFailure(new ProcedureException(ProcedureMessages.REMOVE_DATA_NODE_FAILED + state)); + // Rollback support permits failure cleanup; transient execution errors still retry here. + LOG.error( + ProcedureMessages.LOG_RETRIEVABLE_ERROR_TRYING_REMOVE_DATA_NODE_ARG_STATE_ARG_4EFEB850, + removedDataNodes, + state, + e); + if (getCycles() > RETRY_THRESHOLD) { + setFailure(new ProcedureException(ProcedureMessages.STATE_STUCK_AT + state)); } else { - LOG.error( - ProcedureMessages.LOG_RETRIEVABLE_ERROR_TRYING_REMOVE_DATA_NODE_ARG_STATE_ARG_4EFEB850, - removedDataNodes, - state, - e); - if (getCycles() > RETRY_THRESHOLD) { - setFailure(new ProcedureException(ProcedureMessages.STATE_STUCK_AT + state)); - } else { - setNextState(state); - } + setNextState(state); } } return Flow.HAS_MORE_STATE; @@ -291,7 +288,9 @@ protected long getRollbackRetryTimeout() { @Override protected boolean isRollbackSupported(RemoveDataNodeState state) { - return false; + // A failed migration child must still trigger node cleanup. This restores node statuses and + // stops drained nodes without undoing completed region migrations. + return state == RemoveDataNodeState.STOP_DATA_NODE; } /** diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodePersistenceTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodePersistenceTest.java index 6ec101619174..e3ff29892844 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodePersistenceTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/node/RemoveDataNodePersistenceTest.java @@ -420,12 +420,14 @@ public void testProcedureExecutorCanActuallyRetryCompensationCommitFailure() thr failStatusWrite = true; TestProcedure procedure = procedure(NodeStatus.Running, RemoveDataNodeState.STOP_DATA_NODE); procedure.step(env); + assertFalse("A transient cleanup failure must remain retryable", procedure.isFailed()); assertEquals( "The state-machine executor must retain the failed compensation step", RemoveDataNodeState.STOP_DATA_NODE, procedure.state()); failStatusWrite = false; procedure.step(env); + assertFalse("Successful cleanup retry must not leave a failure", procedure.isFailed()); assertStates(FIRST, NodeStatus.Running, NodeStatus.Running, null); }