Fixed multiple configNode bugs#17609
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #17609 +/- ##
============================================
+ Coverage 40.90% 40.95% +0.05%
Complexity 2610 2610
============================================
Files 5186 5186
Lines 351420 351563 +143
Branches 44991 45018 +27
============================================
+ Hits 143758 143995 +237
+ Misses 207662 207568 -94 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
CRZbulabula
left a comment
There was a problem hiding this comment.
Overall
This PR fixes 6 real correctness bugs in ConfigNode (WAL ordering, log sorting, unchecked consensus writes, off-by-one, concurrent snapshot, pipe-listener failure masking). Changes are well-structured, rollback logic is carefully designed, and test coverage for core scenarios is solid.
Inline comments below cover a few items worth attention before merge.
| if (persistStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { | ||
| return persistStatus; | ||
| } | ||
| } |
There was a problem hiding this comment.
WAL replay idempotency requirement
With the new write-ahead ordering (persist → execute), if persistPlanForSimpleConsensus succeeds at line 125 but executor.executeNonQueryPlan fails at line 133, the plan is already persisted in WAL and will be replayed on restart.
This is correct WAL semantics, but it introduces a hard requirement: all ConfigPhysicalPlan implementations must be idempotent under replay. For example, a RegisterDataNodePlan replayed against an already-registered node must not fail or double-register.
Is this idempotency property currently guaranteed across all ConfigPhysicalPlan types? If not, this could cause issues on crash recovery in edge cases.
| ByteBuffer buffer = plan.serializeToByteBuffer(); | ||
| buffer.position(buffer.limit()); | ||
| simpleLogWriter.write(buffer); | ||
| simpleLogWriter.force(); |
There was a problem hiding this comment.
force() on every write makes scheduled flush redundant
Now that every write is synchronously forced here, the scheduled flushWALForSimpleConsensus thread (lines 447-455) becomes redundant — it calls simpleLogWriter.force() periodically, but there's nothing left to flush.
This is harmless (double-force is idempotent) but worth either:
- Removing the scheduled thread to avoid confusion, or
- Adding a brief comment explaining the intentional belt-and-suspenders approach.
For ConfigNode metadata operations (low write frequency), the per-write force() is the right durability choice.
| "Persist current ConfigPhysicalPlan for ConfigNode SimpleConsensus mode failed", e); | ||
| return new TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()) | ||
| .setMessage( | ||
| "Persist ConfigNode SimpleConsensus log failed: " + String.valueOf(e.getMessage())); |
There was a problem hiding this comment.
Nit: String.valueOf(e.getMessage()) is redundant — string concatenation with + already handles null by converting to "null". Can simplify to:
"Persist ConfigNode SimpleConsensus log failed: " + e.getMessage()| final List<RegionMaintainTask> copiedRegionMaintainTaskList; | ||
| synchronized (regionMaintainTaskList) { | ||
| copiedRegionMaintainTaskList = new ArrayList<>(regionMaintainTaskList); | ||
| } |
There was a problem hiding this comment.
Good fix — synchronized copy before iterating. One minor observation: this copies the entire list under the lock. If regionMaintainTaskList can grow very large, this could cause a brief pause. In practice, for ConfigNode this list is typically small, so this is fine. Just noting for future awareness.
| } | ||
| }); | ||
| return result.getAndIncrement(); | ||
| return result.get(); |
# Conflicts: # iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/statemachine/ConfigRegionStateMachine.java # iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/node/AddConfigNodeProcedure.java
luoluoyuyu
left a comment
There was a problem hiding this comment.
Review summary
Fixes several ConfigNode correctness issues including WAL persist-before-execute and rollback on execute failure. Before merge, document or test that all ConfigPhysicalPlan types are idempotent under WAL replay when persist succeeds and execute fails.
Also resolve CI failures in this PR.
| protected TSStatus write(ConfigPhysicalPlan plan) { | ||
| SimpleConsensusPersistResult persistResult = null; | ||
| if (ConsensusFactory.SIMPLE_CONSENSUS.equals(CONF.getConfigNodeConsensusProtocolClass())) { | ||
| persistResult = persistPlanForSimpleConsensus(plan); |
There was a problem hiding this comment.
With persist before execute, a successful persistPlanForSimpleConsensus followed by a failed executeNonQueryPlan leaves the plan in WAL and it will be replayed on restart. Every ConfigPhysicalPlan executed on replay must be idempotent. Please add an audit or tests for the plan types touched by this PR.
|
|
||
| TSStatus result; | ||
| try { | ||
| result = executor.executeNonQueryPlan(plan); |
There was a problem hiding this comment.
rollbackFailedPlanForSimpleConsensus on execute failure is the right safety net. Ensure rollback failure paths are logged clearly enough for operators when WAL and in-memory state may diverge.
# Conflicts: # iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
|
Addressed the review feedback and pushed the updates. Changes:
Verification:
Current CI note: the Simple (17) failures were checkout/network failures on self-hosted runners (gnutls_handshake before tests started). I reran the failed jobs. todo-check has passed; the remaining jobs are still pending. |
|
# Conflicts: # iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/statemachine/ConfigRegionStateMachine.java # iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java



Description
This PR has:
for an unfamiliar reader.
for code coverage.
Key changed/added classes (or packages if there are too many classes) in this PR