Add KV unit test reproducing stale pending tx (#8293) - #8295
Add KV unit test reproducing stale pending tx (#8293)#8295Amaury Chamayou (achamayou) wants to merge 5 commits into
Conversation
A transaction which takes its version before a view change, but reaches Store::commit() after it, is not caught by the stale-view check, because that check is also gated on the node still being primary. Its entry is parked in pending_txs behind the hole the rollback left, survives the next election because a rollback which discards nothing returns early without clearing pending_txs, and is then replicated by the first transaction of the new term. The new case reproduces this against a real ccf::kv::Store and the existing stub consensus, using a write set observer to drive the view change at the point another thread would be parked mid-commit. Its assertions record the current behaviour, marked BUG where incorrect. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
A couple of the new test’s messages/assertions are misleading/ambiguous in ways that reduce the test’s value as a clear reproduction and future regression indicator.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a new KV-only unit test in kv_test to deterministically reproduce issue #8293 (stale pending transactions surviving a rollback/election boundary and being replicated in a later term), using StubConsensus state transitions and a write-set observer to trigger the view change mid-commit.
Changes:
- Add a new test case covering the “version allocated before view change,
Store::commit()reached after view change” interleaving. - Assert today’s observed (buggy) outcomes to document the failure mode and make future fixes explicitly update expectations.
Custom instructions used:
.github/copilot-instructions.md.github/instructions/reviewing.instructions.md
File summaries
| File | Description |
|---|---|
| src/kv/test/kv_test.cpp | Adds a new KV unit test that reproduces #8293 by simulating rollback/election ordering and observing stale pending-tx replication effects. |
Review details
Suppressed comments (1)
src/kv/test/kv_test.cpp:3167
- The final assertion only checks replicated_to() == 4, which is already true immediately before this write in the buggy path. Capturing the pre-write value and asserting it does not change makes it explicit that this commit was not handed to consensus (and makes the intent of the comment unambiguous).
REQUIRE(write("lost", "4") == ccf::kv::CommitResult::SUCCESS);
CHECK(read("lost") == "4");
// BUG (#8293): reported as committed, but never handed to consensus
CHECK(replicated_to() == 4);
- Files reviewed: 1/1 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.
The test previously recorded the current behaviour and passed. Flip the expectations to what the store should do, so it is a failing repro of #8293 until the defect is fixed. Also count the entries handed to consensus, rather than only the seqno reached. The lost follow-up transaction is invisible to the seqno alone, because the entry already sitting at that seqno is the discarded write. Five divergences are now reported: - the stale write returns SUCCESS rather than FAIL_NO_REPLICATE - the new term's first write replicates two entries rather than one - it reaches seqno 4 rather than 3 - the store version trails what has been replicated - the write after it is never handed to consensus Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject transactions whose view no longer matches the store before they enter the pending replication queue, regardless of leadership state. Extend the regression to cover all leadership states and sequence-number reuse after rollback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve both sides of the release-note conflict, move the pending fix to 7.0.15, and synchronize the Python package version. Name the regression's retained boundary rollback_seqno rather than implying StubConsensus has committed those entries. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Include the public-header helper tests added to main while the PR update was being prepared. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject stale-view transactions in
Store::commit()regardless of node role, under the existing version lock and before updatinglast_committableor inserting intopending_txs. This prevents rolled-back writes from being replicated after a later election and blocking subsequent replication.Closes #8293.
Validation:
kv_testandhistory_testpass viatests.sh; all 14scripts/ci-checks.sh -fgroups pass (WSL, Clang 21.1.8, Debug,USE_SNMALLOC=OFF).