Files
seaweedfs/weed/worker/tasks/erasure_coding/planning.go
T
Chris LuandGitHub 691e601e6f fix(ec): prefer credible replica as canonical metric in EC detection (#9717)
* fix(ec): prefer credible replica as canonical metric in EC detection

An interrupted encode can leave a 0-byte .dat replica behind. When that
stub sits on a lower-sorting server than the real replica, the
lowest-server canonical pick reported Size=0, tripped the min-size gate,
and the volume was stranded in skippedTooSmall: detection never proposed
an encode, so the partial EC shards were never cleared and re-distribute
kept hitting the mounted-volume guard.

selectCanonicalMetric now prefers the lowest-server credible replica
(data-bearing, not already EC), falling back to the lowest-server metric
only when nothing is credible so the downstream gates skip as before. A
leftover EC shard set on a lower server no longer short-circuits the
volume at the IsECVolume guard either, so the orphan-source cleanup and
re-encode paths get their chance.

* fix(ec): treat a bare superblock .dat as a stub too

An interrupted encode or copy can write the 8-byte superblock and then
fail, leaving an 8-byte .dat with no data. isStubReplica used a strict <
so that file slipped through as credible, could win the canonical pick on
a low server, and re-tripped the min-size gate. Use <= the superblock so a
data-less .dat never shadows a real replica.
2026-05-28 13:06:21 -07:00

44 lines
1.6 KiB
Go

package erasure_coding
import (
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
"github.com/seaweedfs/seaweedfs/weed/worker/types"
)
// isStubReplica reports whether a regular replica's .dat is too small to hold
// any data — at most a bare superblock. An interrupted encode or copy can
// leave a 0-byte .dat, or write the 8-byte superblock and then fail; either
// way the file is not an encode source and must not be counted toward
// size/fullness checks.
func isStubReplica(size uint64) bool {
return size <= uint64(super_block.SuperBlockSize)
}
// selectCanonicalMetric picks the metric that drives the encode checks and
// names the encode source server. It prefers the lowest-server credible
// replica — data-bearing and not already EC — so a 0-byte stub or a leftover
// EC shard set sharing the volume id cannot become canonical and strand the
// volume (a stub trips the min-size gate; an EC metric trips the IsECVolume
// guard, hiding the volume from both orphan-source cleanup and re-encode).
// When nothing is credible there is nothing to encode, so the lowest-server
// metric is returned unchanged and the downstream gates make the skip
// decision as before.
func selectCanonicalMetric(group []*types.VolumeHealthMetrics) *types.VolumeHealthMetrics {
var lowest, credible *types.VolumeHealthMetrics
for _, m := range group {
if lowest == nil || m.Server < lowest.Server {
lowest = m
}
if m.IsECVolume || isStubReplica(m.Size) {
continue
}
if credible == nil || m.Server < credible.Server {
credible = m
}
}
if credible != nil {
return credible
}
return lowest
}