Skip to content

[core] MultiAtrunc core implementation - #84

Open
williamwutq wants to merge 3 commits into
masterfrom
multiatrunc
Open

williamwutq wants to merge 3 commits into
masterfrom
multiatrunc

Conversation

@williamwutq

Copy link
Copy Markdown
Owner

Description: Adding multi-atrunc functionality to BStack api, implemented with a WIP journaling with a new wip_aux.

New Feature: Yes
Important Feature: No
Type: Core - Atomic
Feature Flags: set + atomic
Breaking change: No
New Types: None
Rust Only: No
Fuzz: Not needed
Safety Review: Needed: Crash Safety, Invariants, Concurrency

@williamwutq williamwutq self-assigned this Sep 14, 2026
@williamwutq williamwutq added this to the bstack 0.5.0 milestone Sep 14, 2026
@williamwutq

Copy link
Copy Markdown
Owner Author

Original PLANNED.md entry

In Section ## `BStackTransaction` — a buffered, crash-atomic transaction object (0.5.0):

Note that compact repeat is also folded in

New journal mode: MultiAtrunc

A general transaction is an atrunc fused with a multi-write, and there is no existing encoding for that. MultiWrite cannot be stretched to cover it: recovery pins block targets to e <= committed_len and always finalises with clen unchanged.

Sketch, following the conventions of the existing modes:

  • wip_aux = u64::MAX - 6, continuing the decrementing sequence. wip_ptr = 32 + clen', non-zero — unambiguous against MultiWrite (always armed with wip_ptr == 0) and against the single-region modes (each keyed by its own aux value).
  • Staging base S = max(clen, clen'), as the splice modes already use, so staging is disjoint from both the old payload and the new one.
  • The staged tail is the existing back-to-back [s | e | data] block sequence from 32 + S to file_size, with validation relaxed from e <= clen to e <= clen'. On a grow, the new tail content is one more block, whose target sits above the old clen.
  • Protocol: set_len to fit staging → stage → sync → arm → sync → replay in tail order → sync → write_header_commit(clen', 0, Set) → sync → truncate to 32 + clen'.
  • Recovery reads clen' from wip_ptr instead of deriving it from the file size. That is what allows an arbitrary block count; the splice modes can derive clen' only because they stage exactly one region.

The mode overwrites committed bytes before its commit point, so WIP.md's Rule 2 applies: a reader that does not recognise the aux value rolls it back and leaves a torn region. That is the reason for the format change.

Compact Repeat staging within a batched commit (0.5.0)

Feature flag: set + atomic.
Breaking change: Yes (on-disk journal format / recovery).

Motivation

A batched commit (the MultiWrite mode backing set_batched and multi-region inplace_gen/process_gen) stages every block as literal bytes. So a Repeat (above) that shares a batch with other writes loses its O(1) staging — it is expanded into the tail as count·len bytes. Keeping the compact form in a batch requires the journal to carry a repeat descriptor(offset, pattern, count) — for that block, not a literal span, and recovery to replay it.

Design

The compact form advances the on-disk format wherever it lives — a new encoding under wip_aux, in the decrementing-sentinel scheme algos/WIP.md already uses for the splice modes — so old binaries must reject a new-format in-progress journal rather than misread it. Only a file with a live in-progress journal at crash time is affected; a cleanly-closed file carries none and stays compatible. copy is out of scope here — if wanted it can be added later the same way, as the batched analogue of the single-region Copy mode.

Open questions

  • Where it lives Three shapes: (a) extend the existing MultiWrite mode so a staged block may be a literal span or a repeat descriptor; (b) a distinct wip_aux mode dedicated to compact fills; or (c) fold it into the proposed 0.5.0 MultiAtrunc mode, which already generalises MultiWrite. (c) avoids a third multi-region mode when MultiAtrunc lands; (a) keeps it usable without waiting on MultiAtrunc.

Comment thread src/test.rs Dismissed
Comment thread src/test.rs Fixed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Fixed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Fixed
Comment thread src/test.rs Fixed

@williamwutq williamwutq left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussions needed; additionally, the new format may want to support direct moves

Comment thread src/io_core.rs Outdated
Comment thread src/io_core.rs
williamwutq and others added 3 commits September 15, 2026 13:20
Address review feedback on the MultiAtrunc journal:

- Move the `MA_LITERAL`/`MA_REPEAT` block-kind tags up to the file-level
  constants block, alongside `HEADER_SIZE`/`ATOMIC_BLOCK`/`MOVE_CHUNK`.
- `MaBlock::Repeat` now carries a logical `pattern_logical` (HEADER_SIZE
  added only at the I/O boundary), matching `Literal`'s `src_logical` and
  the rest of the module; no on-disk change.
- Add an `MA_CYCLE` block kind so a cyclic multi-region rotation lands as a
  block inside the list rather than a separate wip mode. Any number of
  cycles may share one commit; each is self-contained (disjoint regions) and
  carries its own resumable progress counter in the tail, so recovery
  resumes a cycle from its counter instead of restarting it — which is what
  makes the single-region snapshot re-run-safe. Blocks are 8-padded (base
  rounded to `align8(S)`) so the counter update is a non-tearing 8-byte
  write. Writer input generalised to `&[MaSpec]` (`Write` | `Cycle`); the
  recovery walk, `replay_cycle`, `align8`, and `MA_CYCLE` are ungated so a
  cycle armed by a feature-enabled build recovers under any build.

Document the Cycle tail layout, protocol, and recovery in algos/WIP.md.
Cover the writer and recovery (fresh, mid-cycle resume, and corrupt-tail
rollback) with tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
Comment thread src/test.rs Dismissed
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.

2 participants