mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-06-13 23:36:45 +03:00
vacuum: compact a read-only volume when an explicit volumeId is given (#9861)
* vacuum: compact a read-only volume when an explicit volumeId is given The on-demand path no longer skips read-only volumes, so an operator can reclaim a benignly read-only (full/oversized) volume without marking it writable first. The background scan and all-volumes sweep still skip read-only, where the flag usually signals an unhealthy disk. * vacuum: copy locationList under lock for on-demand vacuum The volumeId>0 path passed the live vid2location entry into the async vacuum, where heartbeat-driven Register/UnRegister can mutate the slice concurrently. Snapshot it under accessLock, matching the sweep path.
This commit is contained in:
@@ -240,9 +240,12 @@ func (t *Topology) Vacuum(grpcDialOption grpc.DialOption, garbageThreshold float
|
||||
vid := needle.VolumeId(volumeId)
|
||||
volumeLayout.accessLock.RLock()
|
||||
locationList, ok := volumeLayout.vid2location[vid]
|
||||
if ok {
|
||||
locationList = locationList.Copy()
|
||||
}
|
||||
volumeLayout.accessLock.RUnlock()
|
||||
if ok {
|
||||
t.vacuumOneVolumeId(grpcDialOption, volumeLayout, c, garbageThreshold, locationList, vid, preallocate)
|
||||
t.vacuumOneVolumeId(grpcDialOption, volumeLayout, c, garbageThreshold, locationList, vid, preallocate, false)
|
||||
}
|
||||
} else {
|
||||
t.vacuumOneVolumeLayout(grpcDialOption, volumeLayout, c, garbageThreshold, maxParallelVacuumPerServer, preallocate, automatic)
|
||||
@@ -311,7 +314,7 @@ func (t *Topology) vacuumOneVolumeLayout(grpcDialOption grpc.DialOption, volumeL
|
||||
wg.Add(1)
|
||||
executor.Execute(func() {
|
||||
defer wg.Done()
|
||||
t.vacuumOneVolumeId(grpcDialOption, volumeLayout, c, garbageThreshold, locationList, vid, preallocate)
|
||||
t.vacuumOneVolumeId(grpcDialOption, volumeLayout, c, garbageThreshold, locationList, vid, preallocate, true)
|
||||
// credit the quota
|
||||
for _, dn := range locationList.list {
|
||||
limiterLock.Lock()
|
||||
@@ -336,14 +339,20 @@ func (t *Topology) vacuumOneVolumeLayout(grpcDialOption grpc.DialOption, volumeL
|
||||
|
||||
}
|
||||
|
||||
func (t *Topology) vacuumOneVolumeId(grpcDialOption grpc.DialOption, volumeLayout *VolumeLayout, c *Collection, garbageThreshold float64, locationList *VolumeLocationList, vid needle.VolumeId, preallocate int64) {
|
||||
// skipReadOnly is set by the background scan and all-volumes sweep, where a
|
||||
// read-only flag usually means an unhealthy disk. An explicit volumeId clears
|
||||
// it so a benignly read-only (full/oversized) volume can be reclaimed.
|
||||
func (t *Topology) vacuumOneVolumeId(grpcDialOption grpc.DialOption, volumeLayout *VolumeLayout, c *Collection, garbageThreshold float64, locationList *VolumeLocationList, vid needle.VolumeId, preallocate int64, skipReadOnly bool) {
|
||||
volumeLayout.accessLock.RLock()
|
||||
isReadOnly := volumeLayout.readonlyVolumes.IsTrue(vid)
|
||||
isEnoughCopies := volumeLayout.enoughCopies(vid)
|
||||
volumeLayout.accessLock.RUnlock()
|
||||
|
||||
if isReadOnly {
|
||||
return
|
||||
if skipReadOnly {
|
||||
return
|
||||
}
|
||||
glog.V(0).Infof("vacuuming read-only volume %d on explicit request", vid)
|
||||
}
|
||||
if !isEnoughCopies {
|
||||
glog.Warningf("skip vacuuming: not enough copies for volume:%d", vid)
|
||||
|
||||
Reference in New Issue
Block a user