mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
M1 milestone: failover evidence crosses transport/session seam. Adapter seam (failover_adapter.go): - FailoverEvidenceAdapter: query-side (promotion evidence + replica summary) - FailoverTakeoverAdapter: execution-side (prepare + gate) - FailoverTarget: binds NodeID + both adapters - NewInProcessFailoverTarget: factory for in-process case Transport seam (failover_evidence_transport.go): - FailoverEvidenceTransport: request/response interface with nodeID routing - FailoverEvidenceHandler: server-side registration - InMemoryFailoverEvidenceTransport: first transport impl (in-memory) - NewHybridInProcessFailoverTarget: transport-backed evidence + local takeover Runtime manager (runtime_manager.go): - InProcessRuntimeManager: participant registry + ExecuteFailover entry point - Persisted failover snapshots/results per-volume and global-last All failover paths (session/driver/manager) now go through adapter seam. Old FailoverParticipant preserved as compatibility wrapper only. Phase 18 docs: phase-18.md (M1-M5 structure), log, decisions. Design docs updated: kernel-closure-review, claim-and-evidence ledger. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85 lines
3.1 KiB
Go
85 lines
3.1 KiB
Go
package volumev2
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/seaweedfs/seaweedfs/sw-block/runtime/masterv2"
|
|
"github.com/seaweedfs/seaweedfs/sw-block/runtime/protocolv2"
|
|
)
|
|
|
|
// FailoverEvidenceAdapter is the transport/session-facing query surface used by
|
|
// failover orchestration. Future remote implementations should satisfy this
|
|
// contract without changing failover session logic.
|
|
type FailoverEvidenceAdapter interface {
|
|
QueryPromotionEvidence(masterv2.PromotionQueryRequest) (masterv2.PromotionQueryResponse, error)
|
|
QueryReplicaSummary(protocolv2.ReplicaSummaryRequest) (protocolv2.ReplicaSummaryResponse, error)
|
|
}
|
|
|
|
// FailoverTakeoverAdapter is the selected-primary execution surface used after
|
|
// masterv2 authorizes promotion. Future implementations may be local or remote,
|
|
// but takeover ownership remains on the selected primary side.
|
|
type FailoverTakeoverAdapter interface {
|
|
PreparePrimaryTakeover(PrimaryTakeoverPlan) (ReconstructedPrimaryTruth, error)
|
|
GatePrimaryActivation(volumeName string, truth ReconstructedPrimaryTruth) error
|
|
}
|
|
|
|
// FailoverTarget binds one stable node id to the evidence and takeover adapters
|
|
// used by failover orchestration.
|
|
type FailoverTarget struct {
|
|
NodeID string
|
|
Evidence FailoverEvidenceAdapter
|
|
Takeover FailoverTakeoverAdapter
|
|
}
|
|
|
|
// NewInProcessFailoverTarget builds the first adapter-backed target from one
|
|
// in-process volumev2 node.
|
|
func NewInProcessFailoverTarget(node *Node) (FailoverTarget, error) {
|
|
if node == nil {
|
|
return FailoverTarget{}, fmt.Errorf("volumev2: node is nil")
|
|
}
|
|
if node.NodeID() == "" {
|
|
return FailoverTarget{}, fmt.Errorf("volumev2: node id is required")
|
|
}
|
|
return FailoverTarget{
|
|
NodeID: node.NodeID(),
|
|
Evidence: inProcessFailoverEvidenceAdapter{node: node},
|
|
Takeover: inProcessFailoverTakeoverAdapter{node: node},
|
|
}, nil
|
|
}
|
|
|
|
type inProcessFailoverEvidenceAdapter struct {
|
|
node *Node
|
|
}
|
|
|
|
func (a inProcessFailoverEvidenceAdapter) QueryPromotionEvidence(req masterv2.PromotionQueryRequest) (masterv2.PromotionQueryResponse, error) {
|
|
if a.node == nil {
|
|
return masterv2.PromotionQueryResponse{}, fmt.Errorf("volumev2: in-process evidence node is nil")
|
|
}
|
|
return a.node.QueryPromotionEvidence(req)
|
|
}
|
|
|
|
func (a inProcessFailoverEvidenceAdapter) QueryReplicaSummary(req protocolv2.ReplicaSummaryRequest) (protocolv2.ReplicaSummaryResponse, error) {
|
|
if a.node == nil {
|
|
return protocolv2.ReplicaSummaryResponse{}, fmt.Errorf("volumev2: in-process evidence node is nil")
|
|
}
|
|
return a.node.QueryReplicaSummary(req)
|
|
}
|
|
|
|
type inProcessFailoverTakeoverAdapter struct {
|
|
node *Node
|
|
}
|
|
|
|
func (a inProcessFailoverTakeoverAdapter) PreparePrimaryTakeover(plan PrimaryTakeoverPlan) (ReconstructedPrimaryTruth, error) {
|
|
if a.node == nil {
|
|
return ReconstructedPrimaryTruth{}, fmt.Errorf("volumev2: in-process takeover node is nil")
|
|
}
|
|
return a.node.PreparePrimaryTakeover(plan)
|
|
}
|
|
|
|
func (a inProcessFailoverTakeoverAdapter) GatePrimaryActivation(volumeName string, truth ReconstructedPrimaryTruth) error {
|
|
if a.node == nil {
|
|
return fmt.Errorf("volumev2: in-process takeover node is nil")
|
|
}
|
|
return a.node.GatePrimaryActivation(volumeName, truth)
|
|
}
|