perf(weed/topology): diff a heartbeat without copying the volume map (#10608)

* perf(weed/topology): keep only volume ids in the heartbeat membership set

The map is used solely to test whether a known volume is still present, but it
copied the whole 152-byte VolumeInfo for every volume in the heartbeat. Presize
it too, since the count is known.

BenchmarkSyncDataNodeRegistration/100000Volumes  199670102 B/op -> 180157310 B/op

* perf(weed/topology): diff a heartbeat without copying the volume map

To find volumes the data node no longer reports, UpdateVolumes copied every
VolumeInfo on the node into a fresh slice, then deleted the missing ones one at
a time. At 100k volumes that is a 15MB copy per heartbeat to usually find
nothing. Scan the disk maps in place instead and return only what was removed.

BenchmarkSyncDataNodeRegistration/100000Volumes  180157310 B/op -> 87806436 B/op
This commit is contained in:
Chris Lu
2026-08-07 00:28:32 -07:00
committed by GitHub
parent 3fce1a938d
commit 2ec899bdee
2 changed files with 21 additions and 10 deletions
+6 -10
View File
@@ -78,22 +78,18 @@ func (dn *DataNode) doAddOrUpdateVolume(v storage.VolumeInfo) (isNew, isChanged
// used in master to notify master clients of these changes.
func (dn *DataNode) UpdateVolumes(actualVolumes []storage.VolumeInfo) (newVolumes, deletedVolumes, changedVolumes []storage.VolumeInfo) {
actualVolumeMap := make(map[needle.VolumeId]storage.VolumeInfo)
actualVolumeIds := make(map[needle.VolumeId]struct{}, len(actualVolumes))
for _, v := range actualVolumes {
actualVolumeMap[v.Id] = v
actualVolumeIds[v.Id] = struct{}{}
}
dn.Lock()
defer dn.Unlock()
existingVolumes := dn.getVolumes()
for _, v := range existingVolumes {
vid := v.Id
if _, ok := actualVolumeMap[vid]; !ok {
glog.V(0).Infoln("Deleting volume id:", vid)
disk := dn.getOrCreateDisk(v.DiskType)
disk.DeleteVolumeById(vid)
for _, c := range dn.children {
disk := c.(*Disk)
for _, v := range disk.RemoveVolumesNotIn(actualVolumeIds) {
glog.V(0).Infoln("Deleting volume id:", v.Id)
deletedVolumes = append(deletedVolumes, v)
deltaDiskUsage := &DiskUsageCounts{}
+15
View File
@@ -211,6 +211,21 @@ func (d *Disk) GetVolumes() (ret []storage.VolumeInfo) {
return ret
}
// RemoveVolumesNotIn drops the volumes whose ids are absent from keep and
// returns them, so a heartbeat can be diffed without first copying the whole
// volume map out.
func (d *Disk) RemoveVolumesNotIn(keep map[needle.VolumeId]struct{}) (removed []storage.VolumeInfo) {
d.Lock()
defer d.Unlock()
for vid, v := range d.volumes {
if _, ok := keep[vid]; !ok {
removed = append(removed, v)
delete(d.volumes, vid)
}
}
return removed
}
func (d *Disk) GetVolumesById(id needle.VolumeId) (storage.VolumeInfo, error) {
d.RLock()
defer d.RUnlock()