Skip to content

Fix consensus subscription WAL retention and replay cursor - #19042

Open
Caideyipi wants to merge 2 commits into
masterfrom
fix/subscription-wal-roll-retention-20261028
Open

Caideyipi wants to merge 2 commits into
masterfrom
fix/subscription-wal-roll-retention-20261028

Conversation

@Caideyipi

@Caideyipi Caideyipi commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

When a live WAL rolls after its last ACK, consensus subscription retention can keep the formerly live file pinned even though committed progress already covers it. Replay can also revisit reclaimed predecessor files during successive cursor advances, or fail to realign when pending delivery is one position beyond the live tail.

Recheck the retention boundary after a roll, while keeping the unchanged-progress shortcut only when the boundary is still the current live WAL. Position replay past covered sealed history without reopening an already passed predecessor, and locate the last WAL directly when the target is beyond the live tail. Buffered requests and newly skipped files still require writer-progress coverage, including follower entries without a local search index.

Validation of 135535a5f673846243485bf0e1bbe2bb99e5496b:

  • Local JDK 17 clean reactor build of DataNode and its required IoTDB dependencies passed, with build-cache reuse disabled: mvn -B -ntp -Ddevelocity.enabled=false clean test -pl iotdb-core/datanode -am -Dtest=ConsensusPrefetchingQueueTest,ProgressWALIteratorTest -Dsurefire.failIfNoSpecifiedTests=false -DfailIfNoTests=false -Dtest.port.closed=true -DforkCount=1 (GITHUB_ACTIONS=true).
  • ConsensusPrefetchingQueueTest: 53 tests, zero failures/errors/skips.
  • ProgressWALIteratorTest: 33 tests, zero failures/errors, one existing opt-in performance test skipped.
  • mvn spotless:apply -P with-integration-tests -pl iotdb-core/datanode and git diff --check passed.

The regression coverage includes unchanged ACK progress across a WAL roll, repeated cursor advances after reclaiming predecessor files, tail-plus-one probes after reclaiming covered history, and preservation of uncovered follower entries. No 24-hour endurance run was performed for this update. The results above are local validation; CI is tracked separately.

The PR remains Draft pending a fresh independent review of the review-feedback update.

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.06%. Comparing base (d452ddd) to head (135535a).
⚠️ Report is 20 commits behind head on master.

Files with missing lines Patch % Lines
...cription/broker/consensus/ProgressWALIterator.java 0.00% 5 Missing ⚠️
...on/broker/consensus/ConsensusPrefetchingQueue.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #19042      +/-   ##
============================================
+ Coverage     48.04%   48.06%   +0.02%     
  Complexity      604      604              
============================================
  Files          5570     5572       +2     
  Lines        409051   410022     +971     
  Branches      53848    54061     +213     
============================================
+ Hits         196512   197063     +551     
- Misses       212539   212959     +420     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Caideyipi
Caideyipi marked this pull request as ready for review October 29, 2026 04:16
@Caideyipi

Copy link
Copy Markdown
Collaborator Author

Initial independent self-review completed for efc531082ef8bd2398cb6f4738816542afe670d7, against base 8cdc9681d0141fa51cfd0dc120b67a7383270865. I inspected the complete diff, all four affected files, and the relevant WAL roll, retention, commit, replay, and seek call paths. No actionable source-behavior or test-logic issues were found; no fixes were needed.

  • Retention now rechecks a formerly live WAL after a roll even when ACK progress is unchanged. The old writer is sealed before the new version is published; uncovered requirements, progress rollback, and metadata-read failures remain conservative.
  • Fast-forward distinguishes an already-passed predecessor from a current or deferred reader. Buffered requests and the newly skipped prefix still require writer-progress coverage, including followers without local search indexes. Tail-plus-one positioning preserves those checks. I found no new exception, lock-order, or resource-lifecycle issue in the affected paths.
  • The regression assertions exercise the unchanged-ACK roll, repeated advances after reclaiming the prefix and intermediate file, and tail-plus-one probes after reclaiming covered history. They also retain the uncovered-follower assertion. Static tracing shows where the original logic would fail these assertions; counter-runs against the original implementation were not executed.

Validation:

  • git diff --check passed.
  • The supplied clean-reactor log from a separate source tree reports 86 tests: 85 passed, zero failures/errors, and one existing opt-in performance test skipped. This does not establish an independent clean build of this exact upstream revision.
  • This round's independent clean-reactor attempt timed out fetching the exact source revision before Maven started. The build, focused tests, and original-implementation counter-runs therefore remain unrun. Local fallback lacked sufficient available virtual memory.
  • Upstream CI reports passing JDK 17 unit-test jobs on Linux and Windows. ZH compilation failed at distribution dependency resolution for missing server/CLI/ConfigNode ZIP artifacts. The SonarCloud quality gate remains failed; the retrieved annotations in the affected production files are outside the changed hunks. These statuses are not reported as passing.

The independent review gate passed. I rechecked that the remote head still matched the reviewed revision, marked the PR ready for review, and verified its non-draft state.

Comment on lines -4794 to +4796
if (Objects.equals(lastCommittedProgressForRetention, committedRegionProgress)
&& Objects.nonNull(lastRetainedWalFileForRetention)
&& lastRetainedWalFileForRetention.exists()) {
return false;
}

// The previous boundary still applies while its sealed requirement is uncovered, or while
// it is the current live WAL file. Both cases require monotonically advancing progress.
// it is the current live WAL file. Recheck even unchanged progress: a roll may have sealed
// the formerly live file after its last ACK, making that file reclaimable without new writes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to check only if it is the live WAL file?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in 135535a5f6. The unchanged-progress shortcut now explicitly requires the retained boundary to still be the current live WAL file. After a roll, the version no longer matches, so the sealed boundary is rechecked even without another ACK. The existing cached requirement check still keeps an uncovered sealed file retained.

Comment on lines 356 to 363
private int locateTargetFile(final long targetSearchIndex) {
if (walFiles.length == 0
|| (liveWalNode != null && targetSearchIndex > liveWalNode.getCurrentSearchIndex())) {
if (walFiles.length == 0) {
return -1;
}
// Pending delivery may have advanced one past the live tail. Still realign to its file after
// verifying coverage of the sealed prefix, before committed history can be reclaimed.
return WALFileUtils.binarySearchFileBySearchIndex(walFiles, targetSearchIndex);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to locate the last file directly in this case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in 135535a5f6. When the target is beyond the live search-index tail, locateTargetFile() now returns walFiles.length - 1 directly. advanceTo() still checks buffered requests and writer-progress coverage of the skipped prefix before repositioning, including follower entries without a local search index.

@Caideyipi
Caideyipi marked this pull request as draft October 30, 2026 02:48
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@Caideyipi
Caideyipi marked this pull request as ready for review October 30, 2026 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants