diff --git a/weed/topology/data_node.go b/weed/topology/data_node.go index a1ad201a9..b3f2edda9 100644 --- a/weed/topology/data_node.go +++ b/weed/topology/data_node.go @@ -86,6 +86,7 @@ func (dn *DataNode) UpdateVolumes(actualVolumes []storage.VolumeInfo) (newVolume dn.Lock() defer dn.Unlock() + keptCount := 0 for _, c := range dn.children { disk := c.(*Disk) for _, v := range disk.RemoveVolumesNotIn(actualVolumeIds) { @@ -102,6 +103,13 @@ func (dn *DataNode) UpdateVolumes(actualVolumes []storage.VolumeInfo) (newVolume } disk.UpAdjustDiskUsageDelta(types.ToDiskType(v.DiskType), deltaDiskUsage) } + keptCount += disk.VolumeCount() + } + // Everything still on the node is also in this heartbeat, so the remainder + // is what the node is about to gain. A steady-state heartbeat gains nothing + // and must not allocate here; a reconnecting server gains all of them. + if addedCount := len(actualVolumes) - keptCount; addedCount > 0 { + newVolumes = make([]storage.VolumeInfo, 0, addedCount) } for _, v := range actualVolumes { isNew, isChanged := dn.doAddOrUpdateVolume(v) diff --git a/weed/topology/disk.go b/weed/topology/disk.go index ef5ee0b58..f2bd0f9f2 100644 --- a/weed/topology/disk.go +++ b/weed/topology/disk.go @@ -212,6 +212,12 @@ func (d *Disk) GetVolumes() (ret []storage.VolumeInfo) { return ret } +func (d *Disk) VolumeCount() int { + d.RLock() + defer d.RUnlock() + return len(d.volumes) +} + // 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.