Files
seaweedfs/sw-block/design/v2-session-protocol-shape.md
T
pingqiuandClaude Opus 4.6 d2d57851b0 feat: rebuild MVP — dual-lane session with bitmap protection
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>
2026-04-07 14:30:34 -07:00

299 lines
6.9 KiB
Markdown

# 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:
1. `sync` asks for facts
2. the primary decides the session
3. the replica executes and reports progress
4. data transport stays separate from semantic ack
## Message Families
The preferred bounded surface is:
1. `walData`
- primary -> replica
- steady-state live WAL lane
2. `sync`
- primary -> replica
- bounded fact query
3. `syncAck`
- replica -> primary
- bounded facts only
4. `sessionControl`
- primary -> replica
- start/cancel/supersede one session contract
5. `sessionAck`
- replica -> primary
- accepted/progress/completed/failed
6. `sessionData`
- primary -> replica
- historical repair lane
7. `sessionDataAck` (optional)
- replica -> primary
- transport/window control only
## Ack Separation Rule
These meanings must stay separate:
1. transport ack
2. session ack
3. sync ack
`sessionDataAck` must never imply:
1. quorum eligibility
2. recovery completion
3. return to `keepup`
## Session Decision Rule
The primary should decide from fresh sync facts:
1. `keepup` if normal sync closure is still true
2. `catchup` if the replica is still within recoverable WAL history
3. `rebuild` if 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:
1. network delay
2. short temporary gap
3. recoverable WAL-only replay
It should not be treated as the main recovery framework.
Catch-up uses two WAL lanes:
1. replay lane from `pin_lsn` to frozen `current_lsn1`
2. 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:
1. base lane
- primary exposes a trusted snapshot/CoW view at `base_lsn`
- replica receives extent/base data from that frozen view
2. WAL lane
- replica accepts WAL from `base_lsn`
- replica applies WAL into its local recovery state while base transfer
continues
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:
1. trusted base
2. explicit target
3. live WAL lane
4. single completion boundary accepted by the primary
The data source may vary:
1. `full_copy`
- copy the full base image
2. `snapshot_or_cow`
- copy a trusted frozen snapshot/CoW view
3. `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:
1. WAL-applied LBA => later base-copy data for that LBA must be skipped
2. 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:
1. accepted into the replica's local WAL/recovery truth
2. 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:
1. checkpoint/snapshot at `base_lsn`
2. previously accepted rebuild/session completion at `base_lsn`
Invalid anchor:
1. arbitrary replica-reported old `applied_lsn` with no trusted-base proof
So the optimization rule is:
1. choose trusted `base_lsn`
2. compute changed blocks for `(base_lsn, target_lsn]`
3. copy only that changed-block set as the base lane
4. keep live WAL lane running in parallel
### Data Shape
Conceptually:
1. `rangeBitmap[lsn_range] -> changed_blocks`
2. planner computes `union(changed_blocks over requested range)`
3. 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:
1. rebuild planner
2. storage/checkpoint metadata
3. execution optimization
It does not belong to:
1. engine projection truth
2. session semantic ownership
3. sync-decision semantics
The engine still only needs to know:
1. session kind
2. base boundary
3. target boundary
4. progress/completion/failure
## Failure Rule
Session failure must not silently decide the next semantic state.
`SessionFailed` means only:
1. this primary-issued contract did not complete
After failure:
1. the replica reports fresh facts again
2. the primary re-decides `keepup` / `catchup` / `rebuild`
No local component may self-escalate to semantic `needs_rebuild`.
## Rebuild-Time Ack Rule
During rebuild:
1. the replica may continue applying new WAL
2. the replica must continue reporting session progress
3. the replica must not be treated as normal quorum-eligible sync success until
the rebuild contract closes
So `syncAck` during rebuild should carry:
1. current facts
2. active session state
3. 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:
1. `session_id`
2. `epoch`
3. `replica_id`
4. `kind`
5. `base_lsn`
6. `target_lsn`
7. `deadline_ms`
For rebuild it may also carry:
1. `base_kind`
2. `snapshot_id` or `cow_view_id`
3. `reservation`
### `sessionAck`
The minimum replica response should carry:
1. `session_id`
2. `epoch`
3. `kind`
4. `phase`
5. `accepted | progress | completed | failed`
For progress reporting, the important facts are:
1. `wal_applied_lsn`
2. `base_progress`
3. `base_complete`
4. `achieved_lsn` on 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:
1. assignment truth
2. sync facts and session decision
3. session progress
4. session completion
5. session failure
That reduction is only safe because transport ack, session ack, and sync ack are
kept separate at the protocol boundary.