From a7b0aa89261aabc78725496d021049bf4a197ff6 Mon Sep 17 00:00:00 2001 From: chrislusf Date: Mon, 26 Oct 2026 01:47:00 -0700 Subject: [PATCH] volume: shuffle a copy of cached replica locations for proxy reads LookupVolumeId serves cached location slices shared between lookups; shuffling in place races with concurrent proxied reads of the same volume. --- weed/server/volume_server_handlers_read.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/weed/server/volume_server_handlers_read.go b/weed/server/volume_server_handlers_read.go index c2b7c71ac0..9558d019f6 100644 --- a/weed/server/volume_server_handlers_read.go +++ b/weed/server/volume_server_handlers_read.go @@ -12,6 +12,7 @@ import ( "net/http" "net/url" "path/filepath" + "slices" "strconv" "strings" "sync/atomic" @@ -77,9 +78,12 @@ func (vs *VolumeServer) proxyReqToTargetServer(w http.ResponseWriter, r *http.Re return } if len(lookupResult.Locations) >= 2 { - rand.Shuffle(len(lookupResult.Locations), func(i, j int) { - lookupResult.Locations[i], lookupResult.Locations[j] = lookupResult.Locations[j], lookupResult.Locations[i] + // cached locations are shared between lookups, so shuffle a copy + locations := slices.Clone(lookupResult.Locations) + rand.Shuffle(len(locations), func(i, j int) { + locations[i], locations[j] = locations[j], locations[i] }) + lookupResult.Locations = locations } var targetUrl *url.URL location := fmt.Sprintf("%s:%d", vs.store.Ip, vs.store.Port)