mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
Batch 7: Command dispatch binding extraction - New weed/server/blockcmd package: CommandHandler interface + DispatchCommands - volume_server_block.go applyCoreCommandsWithAssignment delegates to dispatcher - weed/server still owns RecordCommand, EmitCoreEvent, PublishProjection - v2bridge NOT given command-switch or event-emission semantics Phase 16C: Rebuilding assignment enters core command path Phase 16D: Rebuild recovery-task startup is command-driven Phase 16E: Catch-up recovery-task startup is command-driven Engine refinements: - RecoveryTarget on AssignmentDelivered event - shouldStartRecoveryTask / shouldStartReceiver guards - bootstrapReason: awaiting_rebuild_start Bridge/contract updates: - control_adapter.go: refined translation helpers - contract.go: executor port alignment Migration design docs (Batch 1-3 delivered, design artifacts): - v2-first/second/third-migration-batch.md + task-pack.md - v2-assignment-translation-unification.md - v2-execution-muscles-inventory.md - v2-separation-port-layer-audit.md - v2-legacy-runtime-exit-criteria.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
92 lines
3.1 KiB
Go
92 lines
3.1 KiB
Go
package blockvol
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
engine "github.com/seaweedfs/seaweedfs/sw-block/engine/replication"
|
|
)
|
|
|
|
// MasterAssignment represents a block-volume assignment from the master,
|
|
// as delivered via heartbeat response. This is the raw input from the
|
|
// existing master_grpc_server / block_heartbeat_loop path.
|
|
type MasterAssignment struct {
|
|
VolumeName string // e.g., "pvc-data-1"
|
|
Epoch uint64
|
|
Role string // "primary", "replica", "rebuilding"
|
|
PrimaryServerID string // which server is the primary
|
|
ReplicaServerID string // which server is this replica
|
|
DataAddr string // replica's current data address
|
|
CtrlAddr string // replica's current control address
|
|
AddrVersion uint64 // bumped on address change
|
|
}
|
|
|
|
// ControlAdapter converts master assignments into engine AssignmentIntent.
|
|
// Identity mapping: ReplicaID = <volume-name>/<replica-server-id>.
|
|
// This adapter does NOT decide recovery policy — it only translates
|
|
// master role/state into engine SessionKind.
|
|
type ControlAdapter struct{}
|
|
|
|
// NewControlAdapter creates a control adapter.
|
|
func NewControlAdapter() *ControlAdapter {
|
|
return &ControlAdapter{}
|
|
}
|
|
|
|
// MakeReplicaID derives a stable engine ReplicaID from volume + server identity.
|
|
// NOT derived from any address field.
|
|
func MakeReplicaID(volumeName, serverID string) string {
|
|
return fmt.Sprintf("%s/%s", volumeName, serverID)
|
|
}
|
|
|
|
// ReplicaAssignmentForServer builds one engine replica assignment from stable
|
|
// volume/server identity plus endpoint. This is the canonical identity mapping
|
|
// shared by control ingestion and adapter-side assignment rebinding.
|
|
func ReplicaAssignmentForServer(volumeName, serverID string, endpoint engine.Endpoint) engine.ReplicaAssignment {
|
|
return engine.ReplicaAssignment{
|
|
ReplicaID: MakeReplicaID(volumeName, serverID),
|
|
Endpoint: endpoint,
|
|
}
|
|
}
|
|
|
|
// RecoveryTargetForRole maps a role-shaped control input to the bounded engine
|
|
// recovery target. This is a pure translation rule, not a recovery policy
|
|
// decision.
|
|
func RecoveryTargetForRole(role string) engine.SessionKind {
|
|
switch role {
|
|
case "replica":
|
|
return engine.SessionCatchUp
|
|
case "rebuilding":
|
|
return engine.SessionRebuild
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// ToAssignmentIntent converts a master assignment into an engine intent.
|
|
// The adapter maps role transitions to SessionKind but does NOT decide
|
|
// the actual recovery outcome (that's the engine's job).
|
|
func (ca *ControlAdapter) ToAssignmentIntent(primary MasterAssignment, replicas []MasterAssignment) engine.AssignmentIntent {
|
|
intent := engine.AssignmentIntent{
|
|
Epoch: primary.Epoch,
|
|
}
|
|
|
|
for _, r := range replicas {
|
|
replica := ReplicaAssignmentForServer(r.VolumeName, r.ReplicaServerID, engine.Endpoint{
|
|
DataAddr: r.DataAddr,
|
|
CtrlAddr: r.CtrlAddr,
|
|
Version: r.AddrVersion,
|
|
})
|
|
intent.Replicas = append(intent.Replicas, replica)
|
|
|
|
// Map role to recovery intent (if needed).
|
|
kind := RecoveryTargetForRole(r.Role)
|
|
if kind != "" {
|
|
if intent.RecoveryTargets == nil {
|
|
intent.RecoveryTargets = map[string]engine.SessionKind{}
|
|
}
|
|
intent.RecoveryTargets[replica.ReplicaID] = kind
|
|
}
|
|
}
|
|
|
|
return intent
|
|
}
|