mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-22 07:06:51 +00: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>
415 lines
9.5 KiB
Markdown
415 lines
9.5 KiB
Markdown
# V2 Two-Loop Protocol
|
|
|
|
Date: 2026-04-05
|
|
Status: active
|
|
|
|
## Purpose
|
|
|
|
This note fixes the protocol boundary for the next V2 step.
|
|
|
|
The goal is not to finalize every wire field before implementation.
|
|
The goal is to make the ownership boundary stable enough that automata,
|
|
constraints, and runtime packages can be reorganized without mixing identity
|
|
control and replication consensus again.
|
|
|
|
## Core Rule
|
|
|
|
The protocol is split into two loops:
|
|
|
|
1. `Loop 1`: identity control
|
|
2. `Loop 2`: data control
|
|
|
|
These loops must not be collapsed into one heartbeat or one state owner.
|
|
|
|
## Authority Principle
|
|
|
|
Each volume should be treated as a small distributed cluster:
|
|
|
|
1. `masterv2` is the identity authority outside the cluster
|
|
2. the selected primary is the data-control authority inside the cluster
|
|
3. replicas report bounded facts to the primary, not full truth to `masterv2`
|
|
|
|
This means:
|
|
|
|
1. `masterv2` decides who is allowed to own the role
|
|
2. the new primary decides how takeover, catch-up, and rebuild proceed
|
|
3. `masterv2` may query bounded facts for arbitration, but it does not choreograph
|
|
data recovery step by step
|
|
|
|
## Loop 1: Identity Control
|
|
|
|
Owner:
|
|
|
|
- `masterv2 <-> volumev2`
|
|
|
|
Frequency:
|
|
|
|
- low
|
|
- heartbeat scale
|
|
- assignment scale
|
|
- promotion-query scale
|
|
|
|
## Three Control Channels
|
|
|
|
Within `Loop 1`, the control plane should be split into three different
|
|
channels. They must not be collapsed into one message type.
|
|
|
|
### 1. Heartbeat
|
|
|
|
Direction:
|
|
|
|
- `volumev2 -> masterv2`
|
|
|
|
Frequency:
|
|
|
|
- periodic
|
|
- lightweight
|
|
|
|
Purpose:
|
|
|
|
1. liveness detection
|
|
2. compressed outward mode
|
|
3. confirmation that assignment was applied
|
|
|
|
Heartbeat should carry only:
|
|
|
|
1. `NodeID`
|
|
2. per-volume `Mode`
|
|
3. applied `Epoch`
|
|
4. applied `Role`
|
|
5. `RoleApplied`
|
|
6. `ReplicaReady`
|
|
7. optional passive `CommittedLSN` cache
|
|
|
|
Heartbeat should not carry:
|
|
|
|
1. per-replica progress
|
|
2. catch-up targets
|
|
3. rebuild detail
|
|
4. full failover evidence
|
|
|
|
If `CommittedLSN` is carried in heartbeat, it is only a passive cache. The
|
|
authoritative failover-time value still comes from promotion query.
|
|
|
|
### 2. Promotion Query
|
|
|
|
Direction:
|
|
|
|
- `masterv2 -> candidate volumev2`
|
|
- candidate `volumev2 -> masterv2`
|
|
|
|
Frequency:
|
|
|
|
- on demand
|
|
- only during failover or promotion arbitration
|
|
|
|
Purpose:
|
|
|
|
1. obtain fresh failover evidence
|
|
2. avoid treating stale heartbeat cache as authority
|
|
|
|
Candidate response should include:
|
|
|
|
1. `CommittedLSN`
|
|
2. `WALHeadLSN` as a weaker tiebreaker
|
|
3. `Epoch`
|
|
4. `Role`
|
|
5. `ReceiverReady`
|
|
6. bounded eligibility reason if not promotable
|
|
|
|
The promotion query is where fresh identity-loop evidence is collected.
|
|
It is not a replacement for the data-control loop, and it is not a continuous
|
|
replication-progress feed.
|
|
|
|
If heartbeat also carries `CommittedLSN`, promotion query still wins whenever
|
|
fresh arbitration is required.
|
|
|
|
### 3. Assignment
|
|
|
|
Direction:
|
|
|
|
- `masterv2 -> volumev2`
|
|
|
|
Frequency:
|
|
|
|
- on demand
|
|
- role change or membership change
|
|
|
|
Purpose:
|
|
|
|
1. authorize role ownership
|
|
2. fence stale owners
|
|
3. deliver replica-set identity
|
|
|
|
### Master To Volume
|
|
|
|
`masterv2 -> volumev2` carries only:
|
|
|
|
1. `Epoch`
|
|
2. `Role`
|
|
3. `LeaseTTL`
|
|
4. `ReplicaSet` identities and addresses
|
|
|
|
It does not carry:
|
|
|
|
1. per-replica progress
|
|
2. catch-up target history
|
|
3. detailed rebuild plan
|
|
|
|
### Volume To Master
|
|
|
|
`volumev2 -> masterv2` carries only bounded identity evidence:
|
|
|
|
1. applied `Epoch`
|
|
2. applied `Role`
|
|
3. outward `Mode`
|
|
4. `RoleApplied`
|
|
5. `ReplicaReady`
|
|
|
|
This channel must remain lightweight. Fresh failover evidence belongs to the
|
|
promotion-query channel, not the periodic heartbeat.
|
|
|
|
## Loop 2: Data Control
|
|
|
|
Owner:
|
|
|
|
- `primary engine <-> replica engine`
|
|
|
|
Frequency:
|
|
|
|
- high
|
|
- write scale
|
|
- barrier scale
|
|
- reconnect scale
|
|
|
|
This is where replication consensus lives.
|
|
|
|
### Primary To Replica
|
|
|
|
Primary-side data-control messages should cover:
|
|
|
|
1. WAL entry stream
|
|
2. barrier request with `Epoch` and target LSN
|
|
3. reconnect or resume handshake
|
|
4. rebuild/catch-up execution requests when needed
|
|
|
|
### Replica To Primary
|
|
|
|
Replica-side data-control messages should cover:
|
|
|
|
1. `FlushedLSN`
|
|
2. bounded status such as `ok`, `epoch_mismatch`, `timeout`, `fsync_failed`
|
|
3. reconnect gap evidence
|
|
4. coarse local recovery state
|
|
|
|
### Primary-Owned Per-Replica State
|
|
|
|
The primary brain should own:
|
|
|
|
1. `ReplicaFlushedLSN`
|
|
2. `ShippedLSN` as diagnostic only
|
|
3. replica `State`
|
|
4. `CatchUpTarget`
|
|
5. `RetentionFloor`
|
|
6. `LastContactTime`
|
|
|
|
## Role Of Masterv2
|
|
|
|
`masterv2` authorizes:
|
|
|
|
1. who is primary
|
|
2. who is replica
|
|
3. which epoch is active
|
|
4. when stale owners must be fenced
|
|
|
|
`masterv2` must not decide:
|
|
|
|
1. replay from LSN `X` to `Y`
|
|
2. whether the next action is `keepup` or `catchup`
|
|
3. how rebuild is executed
|
|
4. continuous commit progress
|
|
|
|
`masterv2` may query candidates for fresh promotion evidence, but it still does
|
|
not become the owner of replication history.
|
|
|
|
## Reconstruction And Takeover
|
|
|
|
Promotion and reconstruction are related, but they do not have the same owner.
|
|
|
|
### What Masterv2 Leads
|
|
|
|
`masterv2` leads:
|
|
|
|
1. failover detection
|
|
2. epoch fencing
|
|
3. candidate query for fresh promotion evidence
|
|
4. primary selection
|
|
5. assignment of the new primary role
|
|
|
|
### What The New Primary Leads
|
|
|
|
The selected replacement primary leads:
|
|
|
|
1. local assignment realization
|
|
2. collection of self and peer replica summaries
|
|
3. bounded truth reconstruction
|
|
4. fail-closed takeover gating
|
|
5. follow-on `keepup`, `catchup`, or `rebuild` orchestration
|
|
|
|
### Rule
|
|
|
|
`masterv2` may say:
|
|
|
|
1. "you are now the authorized primary candidate for epoch `E`"
|
|
2. "these are the members of the replica set"
|
|
|
|
But `masterv2` must not say:
|
|
|
|
1. "replay from LSN `X` to `Y`"
|
|
2. "use replica `R` as the rebuild source"
|
|
3. "enter `catchup` before `rebuild`"
|
|
4. "the cluster is safe because my last cached view looked healthy"
|
|
|
|
## Role Of Primary Brain
|
|
|
|
The primary brain discovers:
|
|
|
|
1. current replica state
|
|
2. gap or retention situation
|
|
3. barrier success or failure
|
|
4. whether the volume is `keepup`, `catchup`, `degraded`, or `needs_rebuild`
|
|
|
|
The primary brain decides:
|
|
|
|
1. keep shipping
|
|
2. start catch-up
|
|
3. escalate to `needs_rebuild`
|
|
4. start rebuild after role/assignment allows it
|
|
|
|
## Distributed State-Machine Rules
|
|
|
|
### 1. Different Nodes Have Different Views
|
|
|
|
Each node must distinguish:
|
|
|
|
1. local execution truth
|
|
2. last observed peer truth
|
|
3. cluster identity truth from `masterv2`
|
|
|
|
Do not collapse these into one blob.
|
|
|
|
### 2. All Peer Observations Are Epoch-Scoped
|
|
|
|
Any peer observation that affects recovery must be tied to:
|
|
|
|
1. `Epoch`
|
|
2. session or generation token
|
|
|
|
Old-epoch observations must be ignored or fail closed.
|
|
|
|
### 3. New Primary Reconstructs Truth
|
|
|
|
After failover, the new primary must rebuild its own data-control truth from:
|
|
|
|
1. local state
|
|
2. peer summaries
|
|
3. reconnect handshakes
|
|
|
|
It must not trust `masterv2` as a cache of full recovery history.
|
|
It may use `masterv2` only as the source of authorization and replica identity.
|
|
|
|
### 4. Outward Mode Is Compressed Evidence
|
|
|
|
`allocated_only`, `bootstrap_pending`, `publish_healthy`, `degraded`, and
|
|
`needs_rebuild` are public meanings, not the full internal recovery automaton.
|
|
|
|
### 5. Ambiguity Fails Closed
|
|
|
|
When barrier lineage, progress lineage, or epoch lineage is unclear, the system
|
|
must prefer:
|
|
|
|
1. `degraded`
|
|
2. `needs_rebuild`
|
|
3. no promotion without enough eligibility evidence
|
|
|
|
## Constraint Migration
|
|
|
|
Most of the last week's V2 work remains valid. The important change is where
|
|
each constraint belongs.
|
|
|
|
### Keep As-Is
|
|
|
|
These constraints still stand:
|
|
|
|
1. epoch fencing
|
|
2. one active session per replica per epoch
|
|
3. `catchup` and `rebuild` are different paths
|
|
4. fail closed on ambiguous recovery truth
|
|
5. semantics first, adapters later
|
|
|
|
### Move To Loop 1
|
|
|
|
These belong to identity control:
|
|
|
|
1. assignment application
|
|
2. role ownership
|
|
3. lease ownership
|
|
4. stable replica identity and addressing
|
|
5. compressed heartbeat evidence
|
|
6. on-demand promotion query for fresh evidence
|
|
|
|
### Move To Loop 2
|
|
|
|
These belong to data control:
|
|
|
|
1. committed/durable/checkpoint boundaries
|
|
2. barrier result meaning
|
|
3. replica progress
|
|
4. keepup/catchup/rebuild progression
|
|
5. retention-floor and catch-up targeting
|
|
|
|
## Existing V2 Seeds To Reuse
|
|
|
|
The current V2 code already has the right seeds for the primary-led loop:
|
|
|
|
1. `sw-block/engine/replication/state.go`
|
|
2. `sw-block/engine/replication/event.go`
|
|
3. `sw-block/engine/replication/command.go`
|
|
4. `sw-block/engine/replication/sender.go`
|
|
5. `sw-block/engine/replication/session.go`
|
|
6. `sw-block/engine/replication/registry.go`
|
|
|
|
The current MVP already has the right seeds for the identity loop:
|
|
|
|
1. `sw-block/runtime/masterv2/master.go`
|
|
2. `sw-block/runtime/volumev2/control_session.go`
|
|
3. `sw-block/runtime/volumev2/orchestrator.go`
|
|
|
|
## Immediate Next Step
|
|
|
|
Before deeper implementation, the codebase should next define:
|
|
|
|
1. the minimal `Loop 1` contract types in code, split into heartbeat, promotion
|
|
query, and assignment
|
|
2. the minimal `Loop 2` progress and reconnect contract draft
|
|
3. the automata ownership map showing which engine events and commands belong
|
|
to identity control versus data control
|
|
|
|
## Promotion Logic
|
|
|
|
Promotion should use fresh on-demand evidence, not stale heartbeat cache.
|
|
|
|
Recommended judgment order:
|
|
|
|
1. fence the old primary by epoch
|
|
2. query all surviving candidates
|
|
3. reject any candidate with wrong epoch, wrong role lineage, or not-ready
|
|
receiver state
|
|
4. choose the candidate with highest `CommittedLSN`
|
|
5. use `WALHeadLSN` only as a tiebreaker for equally committed candidates
|
|
6. assign new primary role at a new epoch
|
|
|
|
This keeps the durability boundary centered on `CommittedLSN`, which is the
|
|
last LSN that satisfied the configured durability mode such as `sync_all` or
|
|
`sync_quorum`.
|