mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-20 04:54:24 +02:00
ec: compare live idx NeedleId sets before encode (#11812)
* ec: compare live idx NeedleId sets before encode Refuse encode when replicas' live .idx NeedleId sets differ. Walk only live rows (skip deleted and Size<=0) and compare NeedleId, ignoring Size so MIME/flags drift does not abort a matching id set. Mark the volume read-only for encode and reject writes after that. * fix(ec): compare all replicas then pick capacity source Log matching live idx sets with "replicas are consistent" for the shell CI check. After readonly, compare every replica's live NeedleId set, then require the encode source to have FreeVolumeCount>=2. Empty live-idx vs non-empty refuses encode instead of skipping superblock stubs. Drop the FileCount rebind after the idx gate. * volume: mark readonly under the write lock so checked appends finish first * ec: fix readonly deadlock and restore worker-host source preference MarkVolumeReadonly held dataFileAccessLock while calling reopenIdxForWrite, which re-acquires the same mutex and deadlocks TestMarkVolumeReadonlyCanDelete. Split out reopenIdxForWriteLocked for callers already holding the lock, matching the existing Locked pattern. The worker task lost its worker-host source preference when the idx gate replaced the replica union. Late-bind the source to a replica on the worker host using only the checked location set, with no FileCount rebinding. Drop the now-unused helpers, trim comments added by the earlier commits, and rename tests whose names still claimed convergence while asserting refusal. --------- Co-authored-by: Chepurnov Simon <195125934+CHEPURNOV-S-S@users.noreply.github.com> Co-authored-by: Devin <devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
13 files changed
+763
-200
No files matched your search
+11
-7
@@ -327,17 +327,21 @@ func doEcEncode(env *Env, writer io.Writer, volumeIdToCollection map[needle.Volu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync replicas and select the best one for each volume (with highest file count)
|
||||
// This addresses data inconsistency risk in multi-replica volumes (issue #7797)
|
||||
// by syncing missing entries between replicas before encoding
|
||||
// Compare live .idx sets across all replicas, not only the capacity
|
||||
// subset — a filtered-out replica with a divergent live set still gets
|
||||
// deleted below, so it must refuse encode here. The generation host
|
||||
// must come from filteredLocations.
|
||||
bestReplicas := make(map[needle.VolumeId]wdclient.Location)
|
||||
for _, vid := range volumeIds {
|
||||
collection := volumeIdToCollection[vid]
|
||||
|
||||
// Sync missing entries between replicas, then select the best one
|
||||
bestLoc, selectErr := volume_replica.SyncAndSelectBestReplica(env.GrpcDialOption, vid, collection, filteredLocations[vid], "", writer)
|
||||
prefer := filteredLocations[vid][0].Url
|
||||
bestLoc, selectErr := volume_replica.SelectSourceIfIndexesMatch(env.GrpcDialOption, vid, collection, locations[vid], prefer, writer)
|
||||
if selectErr != nil {
|
||||
return nil, fmt.Errorf("failed to sync and select replica for volume %d: %v", vid, selectErr)
|
||||
return nil, fmt.Errorf("failed to compare replica indexes for volume %d: %v", vid, selectErr)
|
||||
}
|
||||
bestLoc, capErr := volume_replica.RequireCapacitySource(vid, bestLoc, filteredLocations[vid])
|
||||
if capErr != nil {
|
||||
return nil, capErr
|
||||
}
|
||||
bestReplicas[vid] = bestLoc
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user