Files
seaweedfs/sw-block/design/v2-two-loop-protocol.md
T
pingqiuandClaude Opus 4.6 b8c6944e3f feat: V2 MVP milestone — masterv2 + volumev2 + in-process failover
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>
2026-04-05 13:08:02 -07:00

9.5 KiB

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.