Skip to content

Fix broken WAL delta after stream records abort#7791

Merged
timvisee merged 14 commits intoabort-stream-records-breaks-wal-deltafrom
fix-abort-stream-records-breaks-wal-delta
Dec 17, 2025
Merged

Fix broken WAL delta after stream records abort#7791
timvisee merged 14 commits intoabort-stream-records-breaks-wal-deltafrom
fix-abort-stream-records-breaks-wal-delta

Conversation

@timvisee
Copy link
Member

@timvisee timvisee commented Dec 16, 2025

Fixes #7787

I suggest to review and merge this into #7787, so that we can merge the fix and test as a whole into dev. See the mentioned PR for more details on the actual bug.

This PR fixes the problem by taking a 'snapshot' of last seen clocks when the replica goes in any non-active state. When doing WAL delta recovery on the replica, we derive the recovery point from the snapshot rather than the actual latest clocks.

When the replica becomes active again we're sure it's in good state. Then the clocks snapshot is cleared.

Relevant test:

pytest tests/consensus_tests/test_shard_wal_delta_transfer.py -k test_abort_stream_records_breaks_wal_delta

All Submissions:

  • Contributions should target the dev branch. Did you create your branch from dev?
  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

New Feature Submissions:

  1. Does your submission pass tests?
  2. Have you formatted your code locally using cargo +nightly fmt --all command prior to submission?
  3. Have you checked your code using cargo clippy --all --all-features command?

Changes to Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Comment on lines 15 to 22
#[serde(from = "ClockMapHelper", into = "ClockMapHelper")]
pub struct ClockMap {
clocks: HashMap<Key, Clock>,
/// Whether this clock map has changed since the last time it was persisted.
/// Optional snapshot with earlier version of clocks
snapshot: Option<HashMap<Key, Clock>>,
/// Whether this clock map has changed since the last time it was persisted
changed: bool,
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Here I persist the optional snapshot together with regular clocks.

It took me a few iterations to finally land here. In my opinion this is the best approach because:

  • we prevent adding new files
  • we prevent conditional flushers
  • we now flush actual and snapshot clocks atomically

@timvisee timvisee changed the title Fix abort stream records breaks wal delta Fix broken WAL delta after stream records abort Dec 16, 2025
This greatly simplifies state handling. It also prevent any kind of
desynchronization because all newest clocks are always persisted
atomically.
@timvisee timvisee force-pushed the fix-abort-stream-records-breaks-wal-delta branch from 97ac0e1 to b67d7dc Compare December 16, 2025 15:52
@timvisee timvisee marked this pull request as ready for review December 16, 2025 15:54
@timvisee timvisee marked this pull request as draft December 16, 2025 15:54
@timvisee timvisee marked this pull request as ready for review December 16, 2025 15:54
@timvisee timvisee merged commit f225e02 into abort-stream-records-breaks-wal-delta Dec 17, 2025
14 checks passed
@timvisee timvisee deleted the fix-abort-stream-records-breaks-wal-delta branch December 17, 2025 10:29
timvisee added a commit that referenced this pull request Dec 17, 2025
* Make set_replica_state async

* Add function called when active state of local replica changes

* Add snapshot for newest clocks

* Bump newest clocks snapshot on replica deactivation

* Use newest clocks snapshot during recovery

* Add enum for specifying whether to take or clear clocks snapshot

* Store clock snapshot inside clock map, removing extra file

This greatly simplifies state handling. It also prevent any kind of
desynchronization because all newest clocks are always persisted
atomically.

* Immediately persist clocks after taking snapshot

* Always update snapshot, only take if missing

* Take clock snapshots through each shard flavor, including proxies

* Propagate dedicated functions for taking and clearing clocks snapshot

* Only persist clocks immediately if changed on snapshot/clear

* Simplify recovery point logic, always take clocks snapshot if exists

* Remove unwrap
timvisee added a commit that referenced this pull request Dec 17, 2025
* Add test to reproduce broken WAL delta after aborting stream records

* Add staging env var to slow down stream records transfers for test

* Tweak test formatting and utilities a bit

* Add comment to test, link to PR describing bug

* Update test so it still succeeds with patched behavior

* Fix broken WAL delta after stream records abort (#7791)

* Make set_replica_state async

* Add function called when active state of local replica changes

* Add snapshot for newest clocks

* Bump newest clocks snapshot on replica deactivation

* Use newest clocks snapshot during recovery

* Add enum for specifying whether to take or clear clocks snapshot

* Store clock snapshot inside clock map, removing extra file

This greatly simplifies state handling. It also prevent any kind of
desynchronization because all newest clocks are always persisted
atomically.

* Immediately persist clocks after taking snapshot

* Always update snapshot, only take if missing

* Take clock snapshots through each shard flavor, including proxies

* Propagate dedicated functions for taking and clearing clocks snapshot

* Only persist clocks immediately if changed on snapshot/clear

* Simplify recovery point logic, always take clocks snapshot if exists

* Remove unwrap

* Fix typo

* Fix doc comment

* Transfer driver is async, use Tokio sleep

* Reduce visibility
timvisee added a commit that referenced this pull request Dec 18, 2025
* Add test to reproduce broken WAL delta after aborting stream records

* Add staging env var to slow down stream records transfers for test

* Tweak test formatting and utilities a bit

* Add comment to test, link to PR describing bug

* Update test so it still succeeds with patched behavior

* Fix broken WAL delta after stream records abort (#7791)

* Make set_replica_state async

* Add function called when active state of local replica changes

* Add snapshot for newest clocks

* Bump newest clocks snapshot on replica deactivation

* Use newest clocks snapshot during recovery

* Add enum for specifying whether to take or clear clocks snapshot

* Store clock snapshot inside clock map, removing extra file

This greatly simplifies state handling. It also prevent any kind of
desynchronization because all newest clocks are always persisted
atomically.

* Immediately persist clocks after taking snapshot

* Always update snapshot, only take if missing

* Take clock snapshots through each shard flavor, including proxies

* Propagate dedicated functions for taking and clearing clocks snapshot

* Only persist clocks immediately if changed on snapshot/clear

* Simplify recovery point logic, always take clocks snapshot if exists

* Remove unwrap

* Fix typo

* Fix doc comment

* Transfer driver is async, use Tokio sleep

* Reduce visibility
@timvisee timvisee mentioned this pull request Dec 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants