From e12ec947477e30c0542876d52293cb494568d3ab Mon Sep 17 00:00:00 2001 From: Robin Tweedie Date: Thu, 15 Oct 2026 14:36:37 +0100 Subject: [PATCH] fix(shell): compare fractional evacuation destination ratios (#11752) --- weed/shell/command_volume_server_evacuate.go | 3 ++- .../shell/command_volume_server_evacuate_test.go | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/weed/shell/command_volume_server_evacuate.go b/weed/shell/command_volume_server_evacuate.go index af0a99974..cd62bf0ed 100644 --- a/weed/shell/command_volume_server_evacuate.go +++ b/weed/shell/command_volume_server_evacuate.go @@ -1,6 +1,7 @@ package shell import ( + "cmp" "flag" "fmt" "io" @@ -273,7 +274,7 @@ func moveAwayOneNormalVolume(commandEnv *CommandEnv, volumeReplicas map[uint32][ } // most empty one is in the front slices.SortFunc(otherNodes, func(a, b *Node) int { - return int(a.localVolumeRatio(maxVolumeCountFn) - b.localVolumeRatio(maxVolumeCountFn)) + return cmp.Compare(a.localVolumeRatio(maxVolumeCountFn), b.localVolumeRatio(maxVolumeCountFn)) }) for i := 0; i < len(otherNodes); i++ { emptyNode := otherNodes[i] diff --git a/weed/shell/command_volume_server_evacuate_test.go b/weed/shell/command_volume_server_evacuate_test.go index 3983c62e1..ba0332398 100644 --- a/weed/shell/command_volume_server_evacuate_test.go +++ b/weed/shell/command_volume_server_evacuate_test.go @@ -5,6 +5,22 @@ import ( "testing" ) +func TestEvacuatePrefersLowerVolumeRatio(t *testing.T) { + volumes := mkByteVolumes(1, 1, 1) + source := makeByteNode("source", 10, 0, 0, volumes) + fuller := makeByteNode("fuller", 10, 0, 0, mkByteVolumes(10, 4, 1)) + emptier := makeByteNode("emptier", 10, 0, 0, mkByteVolumes(20, 2, 1)) + + // Put the 40%-full server first: truncating 0.2 - 0.4 to int makes the ratios tie. + moved, err := moveAwayOneNormalVolume(nil, nil, volumes[0], source, []*Node{fuller, emptier}, false) + if err != nil || !moved { + t.Fatalf("evacuate: moved=%v, err=%v", moved, err) + } + if _, found := emptier.selectedVolumes[volumes[0].Id]; !found { + t.Fatal("expected evacuation to choose the server with lower occupancy") + } +} + func TestVolumeServerEvacuate(t *testing.T) { targetServer := "" volumeRack := "rack1"