mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-03 02:32:35 +01:00
Stable identity on wire: - ServerID fields in proto (replica_server_id, server_id on ReplicaAddrMessage) - volumeServerId wired through volume.go → BlockService.SetServerID - Identity derived from canonical server ID, not transport addresses Assignment convergence: - V2 idempotence via lastAppliedAssignment.equals (full replica set comparison) - setupPrimaryReplication/Multi idempotence guards - ProcessAssignments with V2 + V1 dual-path assignment handling Master-driven control loop: - RecoveryManager: serialized cancel-and-drain via done channels - Per-replica heartbeat state reporting (ReplicaShipperStatus) - masterServerBackend: VolumeBackend calling real MasterServer in-process - RestoreBlockSnapshot RPC (master + volume server proto) QA tests (P10 P1-P4): - Identity: ServerID on wire, fail-closed on missing - Convergence: assignment delivery, epoch monotonicity, registry coherence - Idempotence: repeated assignment, multi-replica set comparison - Control loop: integrationMaster + real allocator + proto round-trip Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
170 lines
5.1 KiB
Go
170 lines
5.1 KiB
Go
package blockvol
|
|
|
|
import (
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
|
|
)
|
|
|
|
// InfoMessageToProto converts a Go wire type to proto.
|
|
func InfoMessageToProto(m BlockVolumeInfoMessage) *master_pb.BlockVolumeInfoMessage {
|
|
return &master_pb.BlockVolumeInfoMessage{
|
|
Path: m.Path,
|
|
VolumeSize: m.VolumeSize,
|
|
BlockSize: m.BlockSize,
|
|
Epoch: m.Epoch,
|
|
Role: m.Role,
|
|
WalHeadLsn: m.WalHeadLsn,
|
|
CheckpointLsn: m.CheckpointLsn,
|
|
HasLease: m.HasLease,
|
|
DiskType: m.DiskType,
|
|
ReplicaDataAddr: m.ReplicaDataAddr,
|
|
ReplicaCtrlAddr: m.ReplicaCtrlAddr,
|
|
HealthScore: m.HealthScore,
|
|
ScrubErrors: m.ScrubErrors,
|
|
LastScrubTime: m.LastScrubTime,
|
|
ReplicaDegraded: m.ReplicaDegraded,
|
|
DurabilityMode: m.DurabilityMode,
|
|
NvmeAddr: m.NvmeAddr,
|
|
Nqn: m.NQN,
|
|
}
|
|
}
|
|
|
|
// InfoMessageFromProto converts a proto to Go wire type.
|
|
func InfoMessageFromProto(p *master_pb.BlockVolumeInfoMessage) BlockVolumeInfoMessage {
|
|
if p == nil {
|
|
return BlockVolumeInfoMessage{}
|
|
}
|
|
return BlockVolumeInfoMessage{
|
|
Path: p.Path,
|
|
VolumeSize: p.VolumeSize,
|
|
BlockSize: p.BlockSize,
|
|
Epoch: p.Epoch,
|
|
Role: p.Role,
|
|
WalHeadLsn: p.WalHeadLsn,
|
|
CheckpointLsn: p.CheckpointLsn,
|
|
HasLease: p.HasLease,
|
|
DiskType: p.DiskType,
|
|
ReplicaDataAddr: p.ReplicaDataAddr,
|
|
ReplicaCtrlAddr: p.ReplicaCtrlAddr,
|
|
HealthScore: p.HealthScore,
|
|
ScrubErrors: p.ScrubErrors,
|
|
LastScrubTime: p.LastScrubTime,
|
|
ReplicaDegraded: p.ReplicaDegraded,
|
|
DurabilityMode: p.DurabilityMode,
|
|
NvmeAddr: p.NvmeAddr,
|
|
NQN: p.Nqn,
|
|
}
|
|
}
|
|
|
|
// InfoMessagesToProto converts a slice of Go wire types to proto.
|
|
func InfoMessagesToProto(msgs []BlockVolumeInfoMessage) []*master_pb.BlockVolumeInfoMessage {
|
|
out := make([]*master_pb.BlockVolumeInfoMessage, len(msgs))
|
|
for i, m := range msgs {
|
|
out[i] = InfoMessageToProto(m)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// InfoMessagesFromProto converts a slice of proto messages to Go wire types.
|
|
func InfoMessagesFromProto(protos []*master_pb.BlockVolumeInfoMessage) []BlockVolumeInfoMessage {
|
|
out := make([]BlockVolumeInfoMessage, len(protos))
|
|
for i, p := range protos {
|
|
out[i] = InfoMessageFromProto(p)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ShortInfoToProto converts a Go short info to proto.
|
|
func ShortInfoToProto(m BlockVolumeShortInfoMessage) *master_pb.BlockVolumeShortInfoMessage {
|
|
return &master_pb.BlockVolumeShortInfoMessage{
|
|
Path: m.Path,
|
|
VolumeSize: m.VolumeSize,
|
|
BlockSize: m.BlockSize,
|
|
DiskType: m.DiskType,
|
|
}
|
|
}
|
|
|
|
// ShortInfoFromProto converts a proto short info to Go wire type.
|
|
func ShortInfoFromProto(p *master_pb.BlockVolumeShortInfoMessage) BlockVolumeShortInfoMessage {
|
|
if p == nil {
|
|
return BlockVolumeShortInfoMessage{}
|
|
}
|
|
return BlockVolumeShortInfoMessage{
|
|
Path: p.Path,
|
|
VolumeSize: p.VolumeSize,
|
|
BlockSize: p.BlockSize,
|
|
DiskType: p.DiskType,
|
|
}
|
|
}
|
|
|
|
// AssignmentToProto converts a Go assignment to proto.
|
|
func AssignmentToProto(a BlockVolumeAssignment) *master_pb.BlockVolumeAssignment {
|
|
pb := &master_pb.BlockVolumeAssignment{
|
|
Path: a.Path,
|
|
Epoch: a.Epoch,
|
|
Role: a.Role,
|
|
LeaseTtlMs: a.LeaseTtlMs,
|
|
ReplicaDataAddr: a.ReplicaDataAddr,
|
|
ReplicaCtrlAddr: a.ReplicaCtrlAddr,
|
|
RebuildAddr: a.RebuildAddr,
|
|
ReplicaServerId: a.ReplicaServerID, // V2: stable identity
|
|
}
|
|
for _, ra := range a.ReplicaAddrs {
|
|
pb.ReplicaAddrs = append(pb.ReplicaAddrs, &master_pb.ReplicaAddrMessage{
|
|
DataAddr: ra.DataAddr,
|
|
CtrlAddr: ra.CtrlAddr,
|
|
ServerId: ra.ServerID, // V2: stable identity
|
|
})
|
|
}
|
|
return pb
|
|
}
|
|
|
|
// AssignmentFromProto converts a proto assignment to Go wire type.
|
|
// Precedence: if ReplicaAddrs is non-empty, use it and ignore scalar fields.
|
|
func AssignmentFromProto(p *master_pb.BlockVolumeAssignment) BlockVolumeAssignment {
|
|
if p == nil {
|
|
return BlockVolumeAssignment{}
|
|
}
|
|
a := BlockVolumeAssignment{
|
|
Path: p.Path,
|
|
Epoch: p.Epoch,
|
|
Role: p.Role,
|
|
LeaseTtlMs: p.LeaseTtlMs,
|
|
RebuildAddr: p.RebuildAddr,
|
|
ReplicaServerID: p.ReplicaServerId, // V2: stable identity
|
|
}
|
|
if len(p.ReplicaAddrs) > 0 {
|
|
// Multi-replica: populate ReplicaAddrs, leave scalar fields empty.
|
|
for _, ra := range p.ReplicaAddrs {
|
|
a.ReplicaAddrs = append(a.ReplicaAddrs, ReplicaAddr{
|
|
DataAddr: ra.DataAddr,
|
|
CtrlAddr: ra.CtrlAddr,
|
|
ServerID: ra.ServerId, // V2: stable identity
|
|
})
|
|
}
|
|
} else {
|
|
// Backward compat: use scalar fields.
|
|
a.ReplicaDataAddr = p.ReplicaDataAddr
|
|
a.ReplicaCtrlAddr = p.ReplicaCtrlAddr
|
|
}
|
|
return a
|
|
}
|
|
|
|
// AssignmentsToProto converts a slice of Go assignments to proto.
|
|
func AssignmentsToProto(as []BlockVolumeAssignment) []*master_pb.BlockVolumeAssignment {
|
|
out := make([]*master_pb.BlockVolumeAssignment, len(as))
|
|
for i, a := range as {
|
|
out[i] = AssignmentToProto(a)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// AssignmentsFromProto converts a slice of proto assignments to Go wire types.
|
|
func AssignmentsFromProto(protos []*master_pb.BlockVolumeAssignment) []BlockVolumeAssignment {
|
|
out := make([]BlockVolumeAssignment, len(protos))
|
|
for i, p := range protos {
|
|
out[i] = AssignmentFromProto(p)
|
|
}
|
|
return out
|
|
}
|
|
|