mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-21 14:46:58 +00:00
Move removed-replica drain and replica-scoped invalidation onto explicit core-command paths so the widened multi-replica runtime no longer depends on coarse host-side recovery handling. Made-with: Cursor
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package blockcmd
|
|
|
|
import (
|
|
engine "github.com/seaweedfs/seaweedfs/sw-block/engine/replication"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/blockvol"
|
|
)
|
|
|
|
// BackendOps owns the concrete backend-facing operations that remain separate
|
|
// from server-side command orchestration.
|
|
type BackendOps interface {
|
|
ApplyRole(assignment blockvol.BlockVolumeAssignment) (bool, error)
|
|
StartReceiver(assignment blockvol.BlockVolumeAssignment) (bool, error)
|
|
ConfigureShipper(volumeID string, replicas []engine.ReplicaAssignment) (executed bool, shipperConnected bool, err error)
|
|
}
|
|
|
|
// RecoveryCoordinator is the runtime recovery surface used by command ops.
|
|
type RecoveryCoordinator interface {
|
|
StartRecoveryTask(replicaID string, assignments []blockvol.BlockVolumeAssignment)
|
|
DrainRecoveryTask(replicaID, reason string)
|
|
ExecutePendingCatchUp(replicaID string, targetLSN uint64) error
|
|
ExecutePendingRebuild(replicaID string, targetLSN uint64) error
|
|
}
|
|
|
|
// ProjectionReader provides access to current core publication state.
|
|
type ProjectionReader interface {
|
|
Projection(volumeID string) (engine.PublicationProjection, bool)
|
|
}
|
|
|
|
// SessionInvalidator invalidates an active sender session.
|
|
type SessionInvalidator interface {
|
|
InvalidateSession(reason string, targetState engine.ReplicaState)
|
|
}
|
|
|
|
// SenderResolver resolves one sender/session invalidator by replica ID.
|
|
type SenderResolver func(replicaID string) SessionInvalidator
|
|
|
|
// ServiceOps composes backend ops with runtime/server dependencies to satisfy
|
|
// the dispatcher Ops interface without requiring a full BlockService pointer.
|
|
type ServiceOps struct {
|
|
backend BackendOps
|
|
recovery RecoveryCoordinator
|
|
projection ProjectionReader
|
|
senderByID SenderResolver
|
|
}
|
|
|
|
func NewServiceOps(
|
|
backend BackendOps,
|
|
recovery RecoveryCoordinator,
|
|
projection ProjectionReader,
|
|
senderByID SenderResolver,
|
|
) *ServiceOps {
|
|
return &ServiceOps{
|
|
backend: backend,
|
|
recovery: recovery,
|
|
projection: projection,
|
|
senderByID: senderByID,
|
|
}
|
|
}
|
|
|
|
func (ops *ServiceOps) ApplyRole(assignment blockvol.BlockVolumeAssignment) (bool, error) {
|
|
if ops == nil || ops.backend == nil {
|
|
return false, nil
|
|
}
|
|
return ops.backend.ApplyRole(assignment)
|
|
}
|
|
|
|
func (ops *ServiceOps) StartReceiver(assignment blockvol.BlockVolumeAssignment) (bool, error) {
|
|
if ops == nil || ops.backend == nil {
|
|
return false, nil
|
|
}
|
|
return ops.backend.StartReceiver(assignment)
|
|
}
|
|
|
|
func (ops *ServiceOps) ConfigureShipper(volumeID string, replicas []engine.ReplicaAssignment) (bool, bool, error) {
|
|
if ops == nil || ops.backend == nil {
|
|
return false, false, nil
|
|
}
|
|
return ops.backend.ConfigureShipper(volumeID, replicas)
|
|
}
|
|
|
|
func (ops *ServiceOps) StartRecoveryTask(replicaID string, assignment blockvol.BlockVolumeAssignment) (bool, error) {
|
|
if ops == nil || ops.recovery == nil {
|
|
return false, nil
|
|
}
|
|
ops.recovery.StartRecoveryTask(replicaID, []blockvol.BlockVolumeAssignment{assignment})
|
|
return true, nil
|
|
}
|
|
|
|
func (ops *ServiceOps) DrainRecoveryTask(replicaID, reason string) (bool, error) {
|
|
if ops == nil || ops.recovery == nil {
|
|
return false, nil
|
|
}
|
|
ops.recovery.DrainRecoveryTask(replicaID, reason)
|
|
return true, nil
|
|
}
|
|
|
|
func (ops *ServiceOps) InvalidateSession(volumeID, replicaID, reason string) (bool, error) {
|
|
if ops == nil || ops.projection == nil || ops.senderByID == nil {
|
|
return false, nil
|
|
}
|
|
if replicaID != "" {
|
|
sender := ops.senderByID(replicaID)
|
|
if sender == nil {
|
|
return false, nil
|
|
}
|
|
sender.InvalidateSession(reason, engine.StateDisconnected)
|
|
return true, nil
|
|
}
|
|
proj, ok := ops.projection.Projection(volumeID)
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
for _, replicaID := range proj.ReplicaIDs {
|
|
sender := ops.senderByID(replicaID)
|
|
if sender == nil {
|
|
continue
|
|
}
|
|
sender.InvalidateSession(reason, engine.StateDisconnected)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (ops *ServiceOps) StartCatchUp(replicaID string, targetLSN uint64) (bool, error) {
|
|
if ops == nil || ops.recovery == nil {
|
|
return false, nil
|
|
}
|
|
if err := ops.recovery.ExecutePendingCatchUp(replicaID, targetLSN); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (ops *ServiceOps) StartRebuild(replicaID string, targetLSN uint64) (bool, error) {
|
|
if ops == nil || ops.recovery == nil {
|
|
return false, nil
|
|
}
|
|
if err := ops.recovery.ExecutePendingRebuild(replicaID, targetLSN); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|