From 91b88262d7a05b6865af748ef466f67c1f14eb76 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 Aug 2025 13:03:53 -0700 Subject: [PATCH] Fix volume allocation with max=0 and minFreeSpace - prevent allocate-then-delete behavior (#7147) * Initial plan * Fix volume allocation with max=0 and minFreeSpace - prevent allocate-then-delete behavior Co-authored-by: chrislusf <1543151+chrislusf@users.noreply.github.com> * improve tests * table driven * Update weed/storage/store.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * add tests * add more tests --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: chrislusf <1543151+chrislusf@users.noreply.github.com> Co-authored-by: chrislu Co-authored-by: Chris Lu Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- weed/storage/store.go | 11 ++++ weed/storage/store_disk_space_test.go | 94 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 weed/storage/store_disk_space_test.go diff --git a/weed/storage/store.go b/weed/storage/store.go index 2d9707571..77cd6c824 100644 --- a/weed/storage/store.go +++ b/weed/storage/store.go @@ -202,6 +202,17 @@ func (s *Store) addVolume(vid needle.VolumeId, collection string, needleMapKind // hasFreeDiskLocation checks if a disk location has free space func (s *Store) hasFreeDiskLocation(location *DiskLocation) bool { + // Check if disk space is low first + if location.isDiskSpaceLow { + return false + } + + // If MaxVolumeCount is 0, it means unlimited volumes are allowed + if location.MaxVolumeCount == 0 { + return true + } + + // Check if current volume count is below the maximum return int64(location.VolumesLen()) < int64(location.MaxVolumeCount) } diff --git a/weed/storage/store_disk_space_test.go b/weed/storage/store_disk_space_test.go new file mode 100644 index 000000000..284657e3c --- /dev/null +++ b/weed/storage/store_disk_space_test.go @@ -0,0 +1,94 @@ +package storage + +import ( + "testing" + + "github.com/seaweedfs/seaweedfs/weed/storage/needle" +) + +func TestHasFreeDiskLocation(t *testing.T) { + testCases := []struct { + name string + isDiskSpaceLow bool + maxVolumeCount int32 + currentVolumes int + expected bool + }{ + { + name: "low disk space prevents allocation", + isDiskSpaceLow: true, + maxVolumeCount: 10, + currentVolumes: 5, + expected: false, + }, + { + name: "normal disk space and available volume count allows allocation", + isDiskSpaceLow: false, + maxVolumeCount: 10, + currentVolumes: 5, + expected: true, + }, + { + name: "volume count at max prevents allocation", + isDiskSpaceLow: false, + maxVolumeCount: 2, + currentVolumes: 2, + expected: false, + }, + { + name: "volume count over max prevents allocation", + isDiskSpaceLow: false, + maxVolumeCount: 2, + currentVolumes: 3, + expected: false, + }, + { + name: "volume count just under max allows allocation", + isDiskSpaceLow: false, + maxVolumeCount: 2, + currentVolumes: 1, + expected: true, + }, + { + name: "max volume count is 0 allows allocation", + isDiskSpaceLow: false, + maxVolumeCount: 0, + currentVolumes: 100, + expected: true, + }, + { + name: "max volume count is 0 but low disk space prevents allocation", + isDiskSpaceLow: true, + maxVolumeCount: 0, + currentVolumes: 100, + expected: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // setup + diskLocation := &DiskLocation{ + volumes: make(map[needle.VolumeId]*Volume), + isDiskSpaceLow: tc.isDiskSpaceLow, + MaxVolumeCount: tc.maxVolumeCount, + } + for i := 0; i < tc.currentVolumes; i++ { + diskLocation.volumes[needle.VolumeId(i+1)] = &Volume{} + } + + store := &Store{ + Locations: []*DiskLocation{diskLocation}, + } + + // act + result := store.hasFreeDiskLocation(diskLocation) + + // assert + if result != tc.expected { + t.Errorf("Expected hasFreeDiskLocation() = %v; want %v for volumes:%d/%d, lowSpace:%v", + result, tc.expected, len(diskLocation.volumes), diskLocation.MaxVolumeCount, diskLocation.isDiskSpaceLow) + } + }) + } +}