Rebuild session protocol implementation for v2-rebuild-mvp-session-protocol.md. New files: - rebuild_bitmap.go: RebuildBitmap — session-scoped dense bitset for WAL-applied LBA tracking. MarkApplied on local WAL write (not receive). ShouldApplyBase returns false for WAL-covered LBAs (WAL always wins). - rebuild_session.go: RebuildSession — replica-side two-line rebuild. WAL lane (ApplyWALEntry) + base lane (ApplyBaseBlock) with bitmap conflict resolution. TryComplete requires BOTH base_complete AND wal_applied_lsn >= target_lsn. Volume-level control surface: StartRebuildSession, ApplyRebuildSessionWALEntry/BaseBlock, MarkRebuildSessionBaseComplete, TryCompleteRebuildSession, CancelRebuildSession, ActiveRebuildSession. - rebuild_mvp_test.go: 4 correctness tests — base+WAL converge, WAL-applied never overwritten by base, bitmap set on applied not received, control surface start/supersede/complete. - rebuild_transport_test.go: 2 transport-level tests — two-line with real WAL shipping, live writes during base copy with bitmap conflict. Design docs: - v2-rebuild-mvp-session-protocol.md: MVP spec with message set, apply rules, completion/failure/crash rules, test matrix - v2-sync-recovery-protocol.md: full protocol context (keepup/catchup/ rebuild unified design, primary decision logic, two-line model) - v2-session-protocol-shape.md: protocol shape overview Protocol engine (reference, not production): - sw-block/protocol/: 7-event engine with ~300 lines, 13 tests 6 rebuild tests pass, all existing component tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.9 KiB
V2 Session Protocol Shape
Date: 2026-04-07 Status: active draft
Implementation-oriented companion:
v2-rebuild-mvp-session-protocol.md— concrete rebuild MVP protocol target
Purpose
This note fixes the current protocol direction for VS-to-VS recovery control so the engine can eventually shrink its semantic surface instead of re-explaining transport/runtime details through many events.
The goal is to keep one clear split:
syncasks for facts- the primary decides the session
- the replica executes and reports progress
- data transport stays separate from semantic ack
Message Families
The preferred bounded surface is:
walData- primary -> replica
- steady-state live WAL lane
sync- primary -> replica
- bounded fact query
syncAck- replica -> primary
- bounded facts only
sessionControl- primary -> replica
- start/cancel/supersede one session contract
sessionAck- replica -> primary
- accepted/progress/completed/failed
sessionData- primary -> replica
- historical repair lane
sessionDataAck(optional)- replica -> primary
- transport/window control only
Ack Separation Rule
These meanings must stay separate:
- transport ack
- session ack
- sync ack
sessionDataAck must never imply:
- quorum eligibility
- recovery completion
- return to
keepup
Session Decision Rule
The primary should decide from fresh sync facts:
keepupif normal sync closure is still truecatchupif the replica is still within recoverable WAL historyrebuildif the replica is below recoverable retained history
The replica does not choose the next session kind.
Recovery Paths
1. Catch-up
catchup is the narrow WAL-only recovery path.
Expected role:
- network delay
- short temporary gap
- recoverable WAL-only replay
It should not be treated as the main recovery framework.
Catch-up uses two WAL lanes:
- replay lane from
pin_lsnto frozencurrent_lsn1 - live lane beyond
current_lsn1
No bitmap is needed because WAL is ordered by LSN.
2. Rebuild
rebuild is the formal primary recovery path.
It should behave as one integrated contract with two concurrent lanes:
- base lane
- primary exposes a trusted snapshot/CoW view at
base_lsn - replica receives extent/base data from that frozen view
- primary exposes a trusted snapshot/CoW view at
- WAL lane
- replica accepts WAL from
base_lsn - replica applies WAL into its local recovery state while base transfer continues
- replica accepts WAL from
This avoids a large delayed post-snapshot catch-up that would pin old WAL too long.
Rebuild Variants
All rebuild variants share the same semantic contract:
- trusted base
- explicit target
- live WAL lane
- single completion boundary accepted by the primary
The data source may vary:
full_copy- copy the full base image
snapshot_or_cow- copy a trusted frozen snapshot/CoW view
delta_blocks_since_base- copy only blocks known to have changed since a trusted base boundary
This is an optimization choice, not a different session truth model.
Bitmap Rule For Rebuild
The replica maintains a bitmap of LBAs already covered by applied WAL.
The rule is:
- WAL-applied LBA => later base-copy data for that LBA must be skipped
- WAL-received-but-not-applied LBA => not protected by bitmap
So the bit is set on applied, not on received.
Meaning of Applied
For this protocol, applied means:
- accepted into the replica's local WAL/recovery truth
- replayable after replica restart
It does not require the update to be flushed into the final extent image before the bitmap may protect the LBA.
Range Bitmap Optimization
Purpose
A persistent range bitmap can turn some rebuilds from "copy the full base" into "copy only blocks changed since a trusted base boundary."
This is a rebuild optimization, not a new engine-level recovery kind.
Trusted-Base Rule
Range-bitmap optimization is only valid relative to a trusted base boundary.
Valid anchors include:
- checkpoint/snapshot at
base_lsn - previously accepted rebuild/session completion at
base_lsn
Invalid anchor:
- arbitrary replica-reported old
applied_lsnwith no trusted-base proof
So the optimization rule is:
- choose trusted
base_lsn - compute changed blocks for
(base_lsn, target_lsn] - copy only that changed-block set as the base lane
- keep live WAL lane running in parallel
Data Shape
Conceptually:
rangeBitmap[lsn_range] -> changed_blocks- planner computes
union(changed_blocks over requested range) - rebuild sends only those blocks from the trusted base image
This is similar in spirit to changed-block tracking or activity-log-assisted resync, but it must remain anchored to one explicit trusted base point.
Layering Rule
rangeBitmap belongs to:
- rebuild planner
- storage/checkpoint metadata
- execution optimization
It does not belong to:
- engine projection truth
- session semantic ownership
- sync-decision semantics
The engine still only needs to know:
- session kind
- base boundary
- target boundary
- progress/completion/failure
Failure Rule
Session failure must not silently decide the next semantic state.
SessionFailed means only:
- this primary-issued contract did not complete
After failure:
- the replica reports fresh facts again
- the primary re-decides
keepup/catchup/rebuild
No local component may self-escalate to semantic needs_rebuild.
Rebuild-Time Ack Rule
During rebuild:
- the replica may continue applying new WAL
- the replica must continue reporting session progress
- the replica must not be treated as normal quorum-eligible sync success until the rebuild contract closes
So syncAck during rebuild should carry:
- current facts
- active session state
- not-ready-for-quorum meaning
Only after the primary accepts SessionCompleted may later syncAck regain
normal quorum semantics.
Minimal Session Shapes
sessionControl
The minimum contract should carry:
session_idepochreplica_idkindbase_lsntarget_lsndeadline_ms
For rebuild it may also carry:
base_kindsnapshot_idorcow_view_idreservation
sessionAck
The minimum replica response should carry:
session_idepochkindphaseaccepted | progress | completed | failed
For progress reporting, the important facts are:
wal_applied_lsnbase_progressbase_completeachieved_lsnon completion
bitmap_coverage may be added later if needed, but it is not required as the
first semantic surface.
Engine Consequence
If this shape is preserved, the engine can eventually reduce its semantic surface to a smaller set of facts:
- assignment truth
- sync facts and session decision
- session progress
- session completion
- session failure
That reduction is only safe because transport ack, session ack, and sync ack are kept separate at the protocol boundary.