Skip to content

overlay: add Overlay::commit_batch - #948

Draft
citizen-stig wants to merge 4 commits into
thrumdev:masterfrom
citizen-stig:nikolai/overlay-commit-batch
Draft

citizen-stig wants to merge 4 commits into
thrumdev:masterfrom
citizen-stig:nikolai/overlay-commit-batch

Conversation

@citizen-stig

@citizen-stig citizen-stig commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds Overlay::commit_batch(overlays, &nomt), which commits a chain of consecutive overlays with one durable write instead of one per overlay.

API

  • The overlays must be consecutive and ordered oldest first, and the parent of the first must already be committed.
  • The whole chain (parent markers and the root chain) is validated under the write lock before anything is marked or written. If the chain is invalid, nothing is committed.
  • A batch of 0 or 1 overlays falls back to Overlay::commit.

Merging

  • Pages: merged in order. A page that is deleted and then recreated within the chain is rewritten in full (every node, zeros included) into its original bucket, so WAL replay cannot retain old contents. A page that is created and then deleted within the chain never had a bucket and is dropped.
  • Values: concatenated oldest first. The beatree sync keeps the last change of each key.

Rollback

  • Each overlay keeps its own delta, so Nomt::rollback(n) steps through the chain the same way as after sequential commits.
  • Rollback::commit takes several deltas. SegmentedLog::append_batch writes them with a single fsync (the old head segment is fsynced first if the batch rotates segments).
  • The writeout now prunes as many deltas as needed to get back under max_rollback_log_len. Before, it pruned at most one.
  • Behaviour change, single commits included: the manifest now records the live range after pruning (rollback_start_live). Before, it recorded the range before pruning, so a reopen could see more than max_rollback_log_len deltas. rollback_writeout_start_and_end is updated accordingly (1 → 2, 2 → 3).

Tests

New nomt/tests/commit_batch.rs:

  • commit_batch_matches_sequential_commits: same values, roots and bucket occupancy as committing one by one, before and after a reopen. The workload is checked to really clear and recreate stored pages.
  • commit_batch_rollback_matches_sequential_commits: rollback of 1..=N steps matches sequential commits, before and after a reopen.
  • commit_batch_rollback_log_shorter_than_chain: a chain longer than the rollback log.
  • commit_batch_rejects_invalid_chain: an invalid chain is rejected and nothing is committed.

Results

TODO: benchtop does not call commit_batch yet. A batch vs sequential durable_commit comparison is needed.

citizen-stig and others added 4 commits October 20, 2026 13:19
Overlay::commit cloned every page and value change before writing them
out. Validate the parent marker and root under the write lock, mark the
overlay committed, then move the changes out. Data is only cloned if a
live overlay still holds it.

Validating before marking also stops a rejected commit from leaving the
overlay marked as committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rollback delta used to be appended and fsynced before the store
commit started. Pass it into Store::commit instead and append it while
bitbox and beatree prepare their writes. All three are joined before
the manifest is written, so the delta is still durable before the
manifest references it.

After the manifest, finish the beatree sync on its thread pool while
bitbox writes the hash-table pages.

FinishedSession::try_commit_nonblocking no longer needs
Rollback::commit_nonblocking: the rollback log is only touched under
the store's sync lock now, so it is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Commit a chain of overlays with one durable write instead of one per
overlay. Page changes are merged in order: a page deleted and recreated
within the chain is rewritten in full into its original bucket, and a
page created and deleted within the chain is dropped. Value changes are
staged oldest first, so the last change of a key wins.

Each overlay keeps its own rollback delta. Rollback::commit now takes
several deltas and appends them with one fsync, and the writeout prunes
as many deltas as needed. The manifest records the live range after
pruning, so reopening does not bring expired deltas back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wb3qFhAoTArSEcSTGVDCu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant