mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
V2 runtime packages: - sw-block/runtime/masterv2: identity authority (desired state, heartbeat handling, promotion arbitration via SelectPromotionCandidate) - sw-block/runtime/volumev2: per-volume micro-cluster shell (node, orchestrator, control session, iSCSI frontend, takeover gate, failover session + driver, replica summary reconstruction) - sw-block/runtime/purev2: RF1 execution shell (engine + store + dispatcher + local boundary observations) - sw-block/runtime/protocolv2: three-channel separation (heartbeat/assignment/query + replica summary) V2 binaries: - sw-block/cmd/v2singleblock: single-node RF1 block server - sw-block/cmd/purev2rf1: minimal RF1 runtime binary Milestone capabilities: - RF1 write/read/sync with engine-driven mode projection - masterv2 ↔ volumev2 heartbeat convergence + assignment reissue - Promotion query with fresh CommittedLSN/WALHeadLSN evidence - Replica summary for bounded takeover reconstruction - Primary-loss reconstruction from peer summaries (fail-closed gate) - In-process failover driver with session observability - Local boundary observations feed engine (Committed/Durable/Checkpoint) Design docs: - v2-two-loop-protocol.md: identity vs data-control separation - v2-automata-ownership-map.md: event/command ownership split - v2-loop1-surface-draft.md: heartbeat/query/assignment field spec - v2-volumev2-single-node-mvp.md: target layering - v2-kernel-closure-review.md: per-volume micro-cluster principle - v2-pure-runtime-rf1-bootstrap.md, v2-capability-map.md, v2-proof-and-retest-pyramid.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
254 lines
4.7 KiB
Markdown
254 lines
4.7 KiB
Markdown
# V2 Loop1 Surface Draft
|
|
|
|
Date: 2026-04-05
|
|
Status: active
|
|
|
|
## Purpose
|
|
|
|
This note turns the two-loop design into a code-facing draft for the current
|
|
`masterv2` and `volumev2` packages.
|
|
|
|
It does not implement the new protocol yet.
|
|
It defines the smallest surface refactor that should happen first.
|
|
|
|
## Goal
|
|
|
|
Replace the current mixed `heartbeat -> assignments` MVP surface with three
|
|
separate `Loop 1` surfaces:
|
|
|
|
1. periodic heartbeat
|
|
2. promotion query
|
|
3. assignment
|
|
|
|
## Current State
|
|
|
|
Today, `masterv2` uses one heartbeat type and one assignment type:
|
|
|
|
- `sw-block/runtime/masterv2/master.go`
|
|
- `sw-block/runtime/volumev2/control_session.go`
|
|
- `sw-block/runtime/volumev2/volume.go`
|
|
|
|
The current heartbeat still mixes:
|
|
|
|
1. applied identity
|
|
2. outward projection naming
|
|
3. fields that should later become failover evidence
|
|
|
|
## Target Surfaces
|
|
|
|
### 1. Heartbeat
|
|
|
|
Purpose:
|
|
|
|
1. liveness
|
|
2. applied identity
|
|
3. outward compressed mode
|
|
|
|
Recommended fields:
|
|
|
|
- `NodeID`
|
|
- `ReportedAt`
|
|
- per-volume:
|
|
- `Name`
|
|
- `Path`
|
|
- `Epoch`
|
|
- `Role`
|
|
- `Mode`
|
|
- `ModeReason`
|
|
- passive `CommittedLSN` cache
|
|
- `RoleApplied`
|
|
- `ReplicaReady`
|
|
|
|
Not included:
|
|
|
|
- per-replica progress
|
|
- catch-up target
|
|
- detailed recovery phase
|
|
|
|
If `CommittedLSN` is present here, it is only a convenience cache for
|
|
`masterv2`. Fresh promotion judgment still uses the query channel.
|
|
|
|
### 2. Promotion Query
|
|
|
|
Purpose:
|
|
|
|
1. fresh promotion evidence
|
|
2. failover arbitration
|
|
|
|
Recommended request:
|
|
|
|
- `VolumeName`
|
|
- `ExpectedEpoch`
|
|
|
|
Recommended response:
|
|
|
|
- `VolumeName`
|
|
- `NodeID`
|
|
- `Epoch`
|
|
- `Role`
|
|
- `CommittedLSN`
|
|
- `WALHeadLSN`
|
|
- `ReceiverReady`
|
|
- `Eligible`
|
|
- `Reason`
|
|
|
|
Rule:
|
|
|
|
- `CommittedLSN` is the primary selection key
|
|
- `WALHeadLSN` is only a tiebreaker
|
|
|
|
### 3. Assignment
|
|
|
|
Purpose:
|
|
|
|
1. authorize role
|
|
2. fence stale owners
|
|
3. deliver member identity
|
|
|
|
Recommended fields:
|
|
|
|
- `Name`
|
|
- `Path`
|
|
- `NodeID`
|
|
- `Epoch`
|
|
- `LeaseTTL`
|
|
- `Role`
|
|
- `ReplicaSet`
|
|
- `CreateOptions`
|
|
|
|
`ReplicaSet` should carry identity plus transport addresses, not progress.
|
|
|
|
## Field Migration From Current MVP
|
|
|
|
### Current `masterv2.VolumeHeartbeat`
|
|
|
|
Today:
|
|
|
|
- `Name`
|
|
- `Path`
|
|
- `Epoch`
|
|
- `Role`
|
|
- `ProjectionMode`
|
|
- `PublicationReason`
|
|
- `RoleApplied`
|
|
|
|
Should become:
|
|
|
|
- `Name`
|
|
- `Path`
|
|
- `Epoch`
|
|
- `Role`
|
|
- `Mode`
|
|
- `ModeReason`
|
|
- `RoleApplied`
|
|
- `ReplicaReady`
|
|
|
|
Interpretation change:
|
|
|
|
- `ProjectionMode` should be renamed to `Mode`
|
|
- `PublicationReason` should stop pretending to be a generic reason field
|
|
- `ReplicaReady` should be explicit on the identity surface
|
|
|
|
### Current `masterv2.VolumeView`
|
|
|
|
Today:
|
|
|
|
- `ObservedEpoch`
|
|
- `ObservedRole`
|
|
- `ProjectionMode`
|
|
- `PublicationReason`
|
|
- `RoleApplied`
|
|
|
|
Should become:
|
|
|
|
- `ObservedEpoch`
|
|
- `ObservedRole`
|
|
- `Mode`
|
|
- `ModeReason`
|
|
- `RoleApplied`
|
|
- `ReplicaReady`
|
|
|
|
Optional later:
|
|
|
|
- bounded cached failover evidence for debugging only
|
|
|
|
### Current `volumev2.Node.Heartbeat()`
|
|
|
|
Current source:
|
|
|
|
- `snap.Status`
|
|
- `snap.Projection`
|
|
|
|
Recommended extraction:
|
|
|
|
- `Mode` from `snap.Projection.Mode.Name`
|
|
- `ModeReason` from `snap.Projection.Mode.Reason`
|
|
- passive `CommittedLSN` cache from local status snapshot
|
|
- `RoleApplied` from `snap.Projection.Readiness.RoleApplied`
|
|
- `ReplicaReady` from `snap.Projection.Readiness.ReplicaReady`
|
|
|
|
Not from heartbeat:
|
|
|
|
- `CatchUpTarget`
|
|
- `RecoveryProgress`
|
|
|
|
`CommittedLSN` may appear in heartbeat as a passive cache only.
|
|
Fresh promotion authority still belongs to the promotion-query channel.
|
|
`CatchUpTarget` and `RecoveryProgress` belong to Loop 2.
|
|
|
|
## Code Refactor Order
|
|
|
|
### Step 1
|
|
|
|
Add a small shared contract package for `Loop 1` types, for example under:
|
|
|
|
- `sw-block/runtime/protocolv2/`
|
|
|
|
Start with:
|
|
|
|
1. `Heartbeat`
|
|
2. `Assignment`
|
|
3. `PromotionQueryRequest`
|
|
4. `PromotionQueryResponse`
|
|
|
|
### Step 2
|
|
|
|
Make `masterv2` use the shared `Loop 1` contract types instead of local ad hoc
|
|
duplicates.
|
|
|
|
### Step 3
|
|
|
|
Make `volumev2` heartbeat generation write to the narrowed heartbeat shape.
|
|
|
|
### Step 4
|
|
|
|
Add a promotion-query interface without implementing full failover yet.
|
|
|
|
The first code slice only needs:
|
|
|
|
1. request and response types
|
|
2. local evidence extraction helper
|
|
3. one focused test proving query returns fresh local evidence
|
|
|
|
## Test Guidance
|
|
|
|
The first code refactor should keep existing control-loop tests and add one new
|
|
test:
|
|
|
|
1. existing heartbeat-assignment convergence should still pass
|
|
2. new promotion-query test should prove:
|
|
- query is separate from heartbeat
|
|
- fresh state is returned at call time
|
|
- heartbeat `CommittedLSN` is only a passive cache
|
|
- `WALHeadLSN` is not part of periodic heartbeat
|
|
|
|
## Non-Goals
|
|
|
|
This draft does not yet define:
|
|
|
|
1. full Loop 2 message schema
|
|
2. full new primary truth reconstruction choreography
|
|
3. quorum-specific `CommittedLSN` algorithm
|
|
|
|
Those come after the `Loop 1` surface is cleanly split.
|