Skip to content

Stop a rollback moving chunk metadata forward - #8244

Merged
Amaury Chamayou (achamayou) merged 2 commits into
mainfrom
achamayou-clamp-chunker-rollback
Sep 4, 2026
Merged

Stop a rollback moving chunk metadata forward#8244
Amaury Chamayou (achamayou) merged 2 commits into
mainfrom
achamayou-clamp-chunker-rollback

Conversation

@achamayou

@achamayou Amaury Chamayou (achamayou) commented Aug 30, 2026

Copy link
Copy Markdown
Member

Stacked on #8243. Review the top commit only; the base PRs must merge first.

Why this is necessary

Store::rollback() has two paths. If the target is below the store''s version it truncates; if the target is at or beyond it, nothing local is discarded and it returns early. Both paths reset the chunker to the rollback target.

For the truncating path that is right. For the early-return path it is not, because the chunker is allowed to lag the store. An entry is assigned a version by next_version() well before Store::commit() records its size, so at any moment the chunker can legitimately be behind. Resetting it to a target at or beyond the store''s version therefore moves it forward, past entries whose sizes were never recorded.

The chunker''s counter is independent of the store''s version and only ever advances, so the offset is permanent. Every subsequent entry is then recorded against the wrong version, transaction_sizes acquires a hole, and get_unchunked_size() silently under-counts - chunk boundaries drift from what the ledger contains, and compacted_to() can prune entries that were never accounted for.

A rollback to exactly the current version is routine: it is how a view change is communicated when there is nothing to truncate.

What changes

Clamp the rollback target to the store''s own version, so a rollback can only ever move chunk metadata back:

chunker->rolled_back_to(std::min<Version>(tx_id.seqno, version));

Why this is minimal

One std::min on the non-truncating path. The truncating path is untouched - there the target is below version by construction, so the clamp would be a no-op.

The alternative, keeping the chunker eagerly in step with allocation rather than with commit, would mean recording sizes for entries that may never be replicated, which is the resurrection problem the previous PR in this stack fixes.

Performance

None. One comparison on a path taken only during a view change.

Testing

kv_test gains "A rollback never moves chunk metadata past the store''s version", covering both a rollback to exactly the current version and one beyond it, then asserting later entries are still recorded against their own version. Single-threaded and deterministic.

Verified that the test fails without the clamp - the chunker ends ahead of the store, and stays ahead - and passes with it.

Labelled run-long-test.


Review stack

These five PRs come from one investigation and are stacked; review and merge in order.

PR Change
#8242 Reject stale-view writes before local commit
#8243 Order chunk metadata and snapshot scheduling with rollback
#8244 Stop a rollback moving chunk metadata forward
#8245 Guard rollback-sensitive transaction flags
#8246 Guard reserved signature side effects

All were found by an interleaving-exploration harness built over the real KV, consensus and history stack (draft #8238). The harness itself is deliberately not included here; these PRs carry only the fixes and the single-threaded regression tests that pin them.

Base automatically changed from achamayou-order-chunk-metadata-rollback to main September 3, 2026 19:54
Copilot AI lite review requested due to automatic review settings September 3, 2026 20:33
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-clamp-chunker-rollback branch 2 times, most recently from 4562e3c to 800dc2c Compare September 3, 2026 20:33

Copilot AI left a comment

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.

🔵 Needs a closer look

It touches subtle rollback/ledger-chunking invariants in the KV store where correctness depends on concurrency/interleaving behavior that warrants final human review.

Pull request overview

Fixes an edge case in ccf::kv::Store::rollback() where a non-truncating rollback (target at/beyond the Store’s current version) could incorrectly advance ledger chunk metadata, potentially desynchronising chunk boundaries from the actual ledger contents.

Changes:

  • Clamp the chunker rollback target on the non-truncating rollback path to min(tx_id.seqno, version) so chunk metadata cannot be moved forward beyond the Store’s current version.
  • Add a kv_test regression asserting that rollbacks to the current version and beyond it do not advance chunk metadata, and that subsequent entries are still chunked against their own versions.
  • Add a corresponding CHANGELOG.md “Fixed” entry for this behavior change.

Custom instructions used:

  • .github/copilot-instructions.md
  • .github/instructions/changelog.instructions.md
  • .github/instructions/reviewing.instructions.md
File summaries
File Description
src/kv/store.h Clamp chunker rollback target on the early-return (non-truncating) rollback path to prevent advancing chunk metadata past the Store’s version.
src/kv/test/kv_test.cpp Add regression test covering rollbacks to current/beyond-current version and verifying chunker stays aligned.
CHANGELOG.md Document the fix in the current release’s “Fixed” section with PR reference.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/kv/store.h Outdated
@achamayou
Amaury Chamayou (achamayou) force-pushed the achamayou-clamp-chunker-rollback branch 2 times, most recently from dbf5127 to 2332cfe Compare September 4, 2026 05:37
A rollback whose target is at or beyond the store's own version discards nothing, but still reset the chunker to that target. The chunker can legitimately lag the store, because an entry is allocated a version well before its size is recorded, so this moved the chunker forward past the store and left a permanent offset that skewed every later chunk boundary.

Clamp the target to the store's version, so a rollback can only ever move chunk metadata back.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 75d99c5d-6efa-4048-8032-8c78b97208d9
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@eddyashton
Eddy Ashton (eddyashton) force-pushed the achamayou-clamp-chunker-rollback branch from 2332cfe to 2d7f285 Compare September 4, 2026 08:30
@achamayou
Amaury Chamayou (achamayou) merged commit be5578e into main Sep 4, 2026
13 checks passed
@achamayou
Amaury Chamayou (achamayou) deleted the achamayou-clamp-chunker-rollback branch September 4, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-long-test Run Long Test job

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants