mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-17 12:46:59 +00:00
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>
8.3 KiB
8.3 KiB
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)
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 —
Eventin → updatedVolumeState+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 (~1–2 hours)
doc.go— invariant list (what must stay true).types.go—SessionKind,SessionPhase,ReplicaState,Endpoint.event.go+command.go— vocabulary of the core: what can be observed, what can be decided.state.go—VolumeState,ReadinessView,BoundaryView,commandState(idempotence keys).engine.go—ApplyEvent,recompute,applyAssignment,primaryEligibleForPublish,bootstrapReason.sender.go(execution APIs +SessionSnapshot) — how session fencing works.registry.go+orchestrator.go— how assignments become senders and recovery runs.- Host: grep
ApplyEvent/v2Core/applyCoreEventinweed/serverto 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
- Define the type in
event.go— implementVolumeID() string. - Add handling in
ApplyEventinengine.go— updateVolumeStatefields only; no side effects. - If the event implies work for the host, emit a
Command(seecommand.go) or reuse an existing one. - Call
recompute(st)if you added fields that affectMode/Publication(or rely on finalrecomputeat end ofApplyEvent— today every path ends withrecompute). - Extend
VolumeState.Snapshot()instate.goif you added new copyable state. - Add/extend tests:
phase14_*_test.goor focused tests inenginepackage. - Wire the host: wherever the observation is detected in
weed/server, enqueueCoreEngine.ApplyEvent(or the project’s adapter) so the event stream is complete.
6. Checklist: changing Mode or Publication semantics
- Read
recomputeandbootstrapReasonend-to-end — they are the single place for outward mode naming on the bounded path. - If you add a new
ModeName, add it instate.goand handle it inrecompute(and any projection consumers). - Do not infer publish health only from shipper logs in random packages — align with
primaryEligibleForPublishor deliberately extend it with newEvents (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
ApplyEventmust be executed or explicitly dropped by policy — silent ignore leads to stuckbootstrap_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
WriteLBAsuccess as commit — corepublish_healthyrequiresDurableLSN > 0for primary path viaprimaryEligibleForPublish; align client docs with barrier/group commit semantics. - Mixing Core and Sender rules — mode in
CoreEngine, per-replica execution inSender; avoid cross-importing the wrong way fromblockvol. - Breaking idempotence —
commandStatetracks 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).