[Storage] Add inactivity floor to qmdb::immutable Commit operation#3588
Conversation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
commonware-mcp | 37bbc72 | Apr 21 2026, 10:24 PM |
Deploying monorepo with
|
| Latest commit: |
37bbc72
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://35da9b51.monorepo-eu0.pages.dev |
| Branch Preview URL: | https://danlaine-immutable-inactivit.monorepo-eu0.pages.dev |
cc085d9 to
ed7df57
Compare
|
As discussed, should we add this to keyless too? |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ea2c3da. Configure here.
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #3588 +/- ##
========================================
Coverage 95.85% 95.86%
========================================
Files 441 442 +1
Lines 171201 172045 +844
Branches 4003 4013 +10
========================================
+ Hits 164113 164933 +820
- Misses 5828 5843 +15
- Partials 1260 1269 +9
... and 9 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|

Summary
qmdb::immutableis an append-only authenticated database where each key is written exactly once. Applications use it for structures like transaction logs -- data that grows monotonically over the lifetime of the system.The problem is that without a notion of an inactivity floor, the entire history must be retained and synced. In a network of replicas, a new node joining must fetch every operation from genesis to construct the current state. As the log grows, this becomes impractical. The database itself cannot determine which operations are "still needed" because, unlike
qmdb::anywhere key overwrites make old operations provably dead, every immutable operation is alive by definition.Only the application knows when old operations become irrelevant. For example, a transaction log might only need the last N blocks of history. This PR lets the application declare that knowledge by specifying an inactivity floor at commit time.
The floor is embedded directly in the
Operation::Commitvariant, making it part of the operation log and root digest. Every replica processing the same sequence of operations arrives at the same floor. This means:Changes
Operation enum
Operationgains aFamilygeneric parameter and theCommitvariant now carries aLocation<F>alongside its optional metadata:The
has_floor()method on theOperationtrait now returnsSome(loc)forCommitinstead ofNone. Both the fixed-size codec (big-endianu64) and variable-size codec (varint) are updated to encode the new field.Immutable struct
A new
inactivity_floor_loc: Location<F>field is added to theImmutablestruct. It is maintained through every state transition:init_from_journal: Reads the floor from the last commit operation. The in-memory snapshot is replayed starting from the floor rather than from the journal's pruning boundary, so keys set before the floor are excluded from the snapshot.apply_batch: Updates the floor from the batch. A monotonicity assertion (checked before any journal mutation) ensures the floor never decreases.rewind: Restores the floor from the target commit operation.from_sync_result: Extracts the floor from the last commit in the synced range and uses it as the snapshot replay start.prune: Now checks againstinactivity_floor_locinstead oflast_commit_loc. The application can only prune up to what it has declared inactive.A new
inactivity_floor_loc()accessor is provided.Batch API
merkleize()takes a newinactivity_floor: Location<F>parameter. The application passes this when building a batch to declare which operations are no longer needed. The floor is embedded in the resultingCommitoperation and stored onMerkleizedBatchfor use byapply_batch.Partially resolves #3538