Skip to content

[storage/qmdb] Add journal snapshots - #4532

Open
danlaine wants to merge 6 commits into
danlaine/batch-read-gatesfrom
danlaine/qmdb-snapshots-3
Open

[storage/qmdb] Add journal snapshots#4532
danlaine wants to merge 6 commits into
danlaine/batch-read-gatesfrom
danlaine/qmdb-snapshots-3

Conversation

@danlaine

@danlaine danlaine commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Part 2 of a 4-PR stack: #4531#4532#4533#4534.

Background

QMDB peers catch up by state sync: they fetch operations plus Merkle proofs and verify them against a root, and serving code hands out that data through the Source trait.

What this adds

Every authenticated family gains snapshot(), which returns an owned immutable snapshot of the database's journal state. The motivation is peer serving: today, serving state-sync requests reads the live database, which means serving contends with the writer and can observe state that is not yet on disk. A snapshot is a standalone object that keeps answering the same reads and proofs while the live database appends, commits, and prunes. #4533 moves peer serving onto these snapshots.

Note this does not snapshot the QMDB's key-value index.

Three pieces of shared machinery change:

  • The merkle Storage trait keys on an associated Family type and gains a default pinned_nodes_at, so a frozen Merkle store and a live one expose the same node access.
  • historical_proof is hoisted from per-family copies into qmdb, so snapshots and live databases share one proof implementation.
  • The compact witness's VerifiedWitness becomes Tip and implements Source directly. Rebuilding a tip now also verifies the persisted commit bytes against the Merkle tip leaf and rejects non-canonical encodings, so a corrupt witness journal fails to reopen with DataCorrupted.

Snapshot -> index rename

To prevent overloading terms, renames QMDB's in-memory index from "snapshot" to "index". Same for associated function names, etc.

@danlaine danlaine self-assigned this Aug 19, 2026
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

Benchmark results

Regressions: 0.

✅ `qmdb::merkleize/v=any::unordered::fixed::mmr k=10000 ch=false s=true cc=true` (2/2 gates passed)
Field Value
Package commonware-storage
Benchmark target qmdb_gungraun
Variant qmdb::merkleize/v=any::unordered::fixed::mmr k=10000 ch=false s=true cc=true
Filter *::bench_merkleize::any_unordered_fixed_mmr
Baseline suite commonware-storage
Gates EstimatedCycles should decrease; tolerance 10.00%; blob_reads should decrease; tolerance 10.00%
Cargo flags --features test-traits
Metric Baseline Current Delta Gate
Ir 13,198,016 13,215,906 +0.14% -
L1hits 16,884,140 16,902,167 +0.11% -
LLhits 97,457 99,202 +1.79% -
RamHits 11,441 11,375 -0.58% -
TotalRW 16,993,038 17,012,744 +0.12% -
EstimatedCycles 17,771,860 17,796,302 +0.14% EstimatedCycles should decrease; tolerance 10.00%
blob_reads 158 158 +0.00% blob_reads should decrease; tolerance 10.00%
✅ `qmdb::merkleize/v=current::ordered::fixed::mmb chunk=256 k=10000 ch=false s=true cc=true` (2/2 gates passed)
Field Value
Package commonware-storage
Benchmark target qmdb_gungraun
Variant qmdb::merkleize/v=current::ordered::fixed::mmb chunk=256 k=10000 ch=false s=true cc=true
Filter *::bench_merkleize::current_ordered_fixed_mmb_chunk_256
Baseline suite commonware-storage
Gates EstimatedCycles should decrease; tolerance 10.00%; blob_reads should decrease; tolerance 10.00%
Cargo flags --features test-traits
Metric Baseline Current Delta Gate
Ir 15,497,455 15,495,641 -0.01% -
L1hits 20,392,197 20,388,924 -0.02% -
LLhits 140,205 146,028 +4.15% -
RamHits 18,432 14,341 -22.20% -
TotalRW 20,550,834 20,549,293 -0.01% -
EstimatedCycles 21,738,342 21,620,999 -0.54% EstimatedCycles should decrease; tolerance 10.00%
blob_reads 235 235 +0.00% blob_reads should decrease; tolerance 10.00%

Baseline commit(s): 789019f13c7f

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
commonware-mcp 91f162f Aug 19 2026, 10:15 PM

@danlaine
danlaine force-pushed the danlaine/qmdb-snapshots-3 branch from 119a9c6 to 0e8a682 Compare August 19, 2026 17:26
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploying monorepo with  Cloudflare Pages  Cloudflare Pages

Latest commit: 91f162f
Status: ✅  Deploy successful!
Preview URL: https://68ed04ec.monorepo-eu0.pages.dev
Branch Preview URL: https://danlaine-qmdb-snapshots-3.monorepo-eu0.pages.dev

View logs

@danlaine
danlaine force-pushed the danlaine/qmdb-snapshots-3 branch 4 times, most recently from 8adfa09 to 5aeecc3 Compare August 19, 2026 21:00
@danlaine danlaine changed the title [storage/qmdb] Add snapshots [storage/qmdb] Add journal snapshots Aug 19, 2026
danlaine and others added 6 commits August 19, 2026 17:51
Every authenticated database family gains snapshot(), an owned immutable
capture of its state: full families freeze the authenticated journal at
its current size (bounds pinned at capture, proofs byte-stable across
later appends, rewrites, and prunes; applied-but-uncommitted operations
are included, and reads from a later-rewound range are unspecified),
and compact families capture the witness tip (the latest commit).
Captures serve reads and proofs through the same Source interface as
the live database, so peer serving can move off the live instance.

Supporting rework: the merkle Storage trait keys on an associated Family
and gains pinned_nodes_at; historical_proof is hoisted to qmdb so
snapshots and live databases share one implementation; the compact
witness's VerifiedWitness becomes Tip, implements Source directly, and
now rejects non-canonical persisted commit bytes on rebuild (a corrupt
journal fails with DataCorrupted instead of reopening). The in-memory
key-to-location map is renamed from snapshot to index throughout (field,
IndexBuild, IndexUndo, telemetry labels, and every comment and test name
that used the old word for it), freeing the word for these captures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q92PhqGoHbWCGHCsBJ7EBU
The remaining comments that used snapshot for the key index, including
the fuzz crate outside the workspace, now say index.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q92PhqGoHbWCGHCsBJ7EBU
Six comments kept their old punctuation through the rename instead of
trading colons for dashes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q92PhqGoHbWCGHCsBJ7EBU
Finish the index rename in three missed comments and inline a
single-caller request check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q92PhqGoHbWCGHCsBJ7EBU
Snapshot inherited the Storage trait's sequential get_nodes, one
awaited journal read per proof node on the serving path. Mirror the
live structure's override, serving memory-resident nodes directly and
batching the rest through one read_many.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q92PhqGoHbWCGHCsBJ7EBU
@danlaine
danlaine force-pushed the danlaine/qmdb-snapshots-3 branch from 5aeecc3 to 91f162f Compare August 19, 2026 22:14
@danlaine
danlaine marked this pull request as ready for review August 19, 2026 22:30
@danlaine danlaine added this to Tracker Aug 19, 2026
@danlaine danlaine moved this to Ready for Review in Tracker Aug 19, 2026
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.35083% with 76 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.55%. Comparing base (80c708d) to head (91f162f).

Files with missing lines Patch % Lines
storage/src/merkle/persisted/full.rs 68.68% 31 Missing ⚠️
storage/src/journal/authenticated.rs 86.16% 22 Missing ⚠️
storage/src/qmdb/compact/witness.rs 96.88% 5 Missing and 2 partials ⚠️
storage/src/qmdb/keyless/compact.rs 96.15% 1 Missing and 3 partials ⚠️
storage/src/merkle/mmr/verification.rs 33.33% 2 Missing ⚠️
storage/src/merkle/storage.rs 87.50% 1 Missing and 1 partial ⚠️
storage/src/qmdb/any/batch.rs 83.33% 1 Missing and 1 partial ⚠️
storage/src/qmdb/any/ordered/mod.rs 60.00% 0 Missing and 2 partials ⚠️
storage/src/qmdb/immutable/compact.rs 97.72% 0 Missing and 2 partials ⚠️
storage/src/qmdb/immutable/mod.rs 98.50% 1 Missing ⚠️
... and 1 more
@@                      Coverage Diff                      @@
##           danlaine/batch-read-gates    #4532      +/-   ##
=============================================================
- Coverage                      95.56%   95.55%   -0.02%     
=============================================================
  Files                            610      610              
  Lines                         278058   278774     +716     
  Branches                        6654     6661       +7     
=============================================================
+ Hits                          265732   266380     +648     
- Misses                         10139    10203      +64     
- Partials                        2187     2191       +4     
Files with missing lines Coverage Δ
storage/src/bitmap/authenticated.rs 92.06% <ø> (ø)
storage/src/index/partitioned/mod.rs 100.00% <ø> (ø)
storage/src/index/partitioned/ordered/mod.rs 99.00% <ø> (ø)
storage/src/index/partitioned/unordered.rs 100.00% <ø> (ø)
storage/src/index/unordered.rs 98.11% <ø> (ø)
storage/src/journal/contiguous/fixed.rs 98.33% <100.00%> (+<0.01%) ⬆️
storage/src/journal/contiguous/mod.rs 92.92% <ø> (ø)
storage/src/journal/contiguous/variable.rs 96.61% <100.00%> (+<0.01%) ⬆️
storage/src/merkle/mmr/full.rs 100.00% <ø> (ø)
storage/src/merkle/persisted/compact.rs 99.42% <100.00%> (ø)
... and 43 more

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 80c708d...91f162f. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready for Review

Development

Successfully merging this pull request may close these issues.

1 participant