Files
seaweedfs/sw-block/design/v2-engine-maintainer-tutorial.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

141 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# V2 Engine — Maintainer Tutorial
Audience: engineers taking over `sw-block/engine/replication` and its integration in `weed/server`.
Goal: know **where truth lives**, **how to read the code in order**, and **where to add new rules** without breaking layering.
---
## 1. Mental model (keep this picture)
```mermaid
flowchart LR
subgraph Control[Cluster control plane]
M[Master: heartbeat, assignment, epoch]
end
subgraph Local[One volume server — local semantics]
CE[CoreEngine: per-volume readiness, boundaries, mode, commands]
OR[RecoveryOrchestrator + Registry + Sender/Session]
end
subgraph Muscle[Data plane — weed/storage/blockvol]
BP[WAL, flush, shipper, receiver, barrier]
end
M -->|AssignmentDelivered / events derived from control| CE
CE -->|Command| BP
OR -->|execution APIs| BP
BP -->|observations as Event| CE
```
- **CoreEngine**: one **reducer** per volume — `Event` in → updated `VolumeState` + `Command` + `PublicationProjection`. No I/O.
- **Sender / Session / Registry / RecoveryOrchestrator**: **per-replica recovery authority** — session phases, fencing, catch-up/rebuild execution, handshake from `RetainedHistory`.
- **blockvol / server**: muscles **execute** commands and **report** facts; they must not silently fork “publication truth” outside events.
See also: `v2-protocol-truths.md`, `v2-two-loop-protocol.md`.
---
## 2. Repository map (what file does what)
| Area | Primary paths | Responsibility |
|------|----------------|----------------|
| Package entry & invariants | `sw-block/engine/replication/doc.go` | Read first — lists ownership/fencing rules. |
| Core shell (Phase 14) | `engine.go`, `state.go`, `event.go`, `command.go`, `projection.go` | Volume-level mode, readiness, boundaries, emitted commands. |
| Per-replica recovery | `sender.go`, `session.go`, `registry.go`, `budget.go`, `rebuild.go`, `outcome.go`, `history.go` | Session FSM, handshake classification, bounded catch-up. |
| Orchestration | `orchestrator.go`, `driver.go`, `executor.go` | `ProcessAssignment`, `ExecuteRecovery`, stepwise recovery plans. |
| Boundaries | `adapter.go` | `StorageAdapter` — engine never reaches into storage directly. |
| Runtime helpers | `engine/replication/runtime/*.go` | Pending/step execution helpers — not the semantic core. |
| Host integration | `weed/server/volume_server_block.go`, `block_recovery.go`, `block_protocol_state.go`, `weed/storage/blockvol/v2bridge` | Wires engine, applies observations, executes commands. |
---
## 3. Suggested first read order (~12 hours)
1. **`doc.go`** — invariant list (what must stay true).
2. **`types.go`** — `SessionKind`, `SessionPhase`, `ReplicaState`, `Endpoint`.
3. **`event.go` + `command.go`** — vocabulary of the core: what can be observed, what can be decided.
4. **`state.go`** — `VolumeState`, `ReadinessView`, `BoundaryView`, `commandState` (idempotence keys).
5. **`engine.go`** — `ApplyEvent`, `recompute`, `applyAssignment`, `primaryEligibleForPublish`, `bootstrapReason`.
6. **`sender.go`** (execution APIs + `SessionSnapshot`) — how session fencing works.
7. **`registry.go` + `orchestrator.go`** — how assignments become senders and recovery runs.
8. **Host**: grep `ApplyEvent` / `v2Core` / `applyCoreEvent` in `weed/server` to see how events are produced.
---
## 4. Where to add a “new rule” (decision tree)
Ask: **what kind of rule is it?**
| Your change is about… | Put it in… | Typical pattern |
|------------------------|------------|-----------------|
| When the volume is `publish_healthy` / `bootstrap_pending`, or how readiness/boundary combine | **`CoreEngine`** — `recompute`, `primaryEligibleForPublish`, or new/extended `Event` handling | Add/adjust `Event`, update `ApplyEvent` branch, extend `recompute`; keep commands **pure** (no I/O). |
| When a replica may receive live WAL tail, catch-up bounds, session invalidation | **`Sender` / `Session`** and/or **`RecoveryOrchestrator`** | Extend phase checks, `checkAuthority`, handshake/budget; **do not** duplicate mode logic in blockvol. |
| Gating execution (e.g. live ship) from host-visible engine snapshots | **`weed/server`** (e.g. protocol execution sync) — **derive** from engine/registry, **set** policy on `BlockVol` | Keep engine free of TCP; host binds policy to data plane. |
| Cluster-wide who is primary / epoch | **Master / assignment path** — not inside `CoreEngine` alone | VS consumes assignment as `AssignmentDelivered` (or equivalent adapter event). |
**Rule of thumb**: if the rule needs **only local observations** already modeled as `Event`, it belongs in **`engine.go`**. If it needs **per-replica session identity or LSN ranges**, it belongs in **`sender.go` / `session.go`**. If it needs **disk retention / pins**, use **`StorageAdapter`** and **`RecoveryDriver`** paths.
---
## 5. Checklist: adding a new **CoreEngine** `Event`
1. Define the type in **`event.go`** — implement `VolumeID() string`.
2. Add handling in **`ApplyEvent`** in **`engine.go`** — update `VolumeState` fields only; no side effects.
3. If the event implies work for the host, emit a **`Command`** (see **`command.go`**) or reuse an existing one.
4. Call **`recompute(st)`** if you added fields that affect `Mode` / `Publication` (or rely on final `recompute` at end of `ApplyEvent` — today every path ends with `recompute`).
5. Extend **`VolumeState.Snapshot()`** in **`state.go`** if you added new copyable state.
6. Add/extend **tests**: `phase14_*_test.go` or focused tests in `engine` package.
7. **Wire the host**: wherever the observation is detected in `weed/server`, enqueue **`CoreEngine.ApplyEvent`** (or the projects adapter) so the event stream is **complete**.
---
## 6. Checklist: changing **Mode** or **Publication** semantics
- Read **`recompute`** and **`bootstrapReason`** end-to-end — they are the **single place** for outward mode naming on the bounded path.
- If you add a new `ModeName`, add it in **`state.go`** and handle it in **`recompute`** (and any projection consumers).
- **Do not** infer publish health only from shipper logs in random packages — align with **`primaryEligibleForPublish`** or deliberately extend it with new `Event`s (e.g. new boundary).
---
## 7. Integration: `weed/server` expectations
- **Assignments** from master should eventually surface as **`AssignmentDelivered`** (or the unified adapter equivalent) with correct **epoch** and **replica IDs**.
- **Observations** (receiver ready, shipper configured/connected, barrier OK/fail, LSN advances) must be **turned into events**; missing events ⇒ core state diverges from reality.
- **Commands** returned by `ApplyEvent` must be **executed or explicitly dropped** by policy — silent ignore leads to stuck `bootstrap_pending`.
Grep starting points: `v2Core`, `ApplyEvent`, `applyCoreEvent`, `coreProj`.
---
## 8. Testing strategy (short)
| Layer | What to prove |
|-------|----------------|
| `engine` package tests | Deterministic transitions: given event list ⇒ final `VolumeState` / projection. |
| Sender/session tests | Session ID fencing, phase transitions, budget escalation. |
| `weed/server` tests | Host wiring: policy + observations ⇒ expected gating or readiness. |
See `v2-proof-and-retest-pyramid.md`.
---
## 9. Common pitfalls
- **Duplicating “truth”** — updating readiness or durable LSN only in ad-hoc variables without emitting **`Event`**.
- **Treating `WriteLBA` success as commit** — core **`publish_healthy`** requires **`DurableLSN > 0`** for primary path via **`primaryEligibleForPublish`**; align client docs with barrier/group commit semantics.
- **Mixing Core and Sender rules** — mode in `CoreEngine`, per-replica execution in `Sender`; avoid cross-importing the wrong way from `blockvol`.
- **Breaking idempotence** — `commandState` tracks what was already commanded; new commands need stable keys (epoch + replica + target LSN where applicable).
---
## 10. Related documents
- `v2-automata-ownership-map.md` — who owns which automaton.
- `v2-session-protocol-shape.md` — current VS-to-VS sync/session/data surface.
- `v2-rebuild-mvp-session-protocol.md` — implementation target for the first rebuild MVP.
- `v2-protocol-aware-execution.md` — host-side execution gating.
- `wal-replication-v2-state-machine.md` — replica FSM (design-level).
- `engine/replication/doc.go` — source-level invariant list (always keep in sync when you change semantics).