mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-16 04:06:44 +00:00
* 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.
44 lines
1.6 KiB
Go
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
|
|
}
|