From 569f203abd94b0f41577d0b7eb6f8f1b0cf9ce2c Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 17 Mar 2026 15:48:09 -0700 Subject: [PATCH] Match Go FindFreeLocation: account for EC shards in free slot calculation Go subtracts EC shard equivalents when computing available volume slots. Rust was only comparing volume count, potentially over-counting free slots on locations with many EC shards. --- seaweed-volume/src/storage/store.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/seaweed-volume/src/storage/store.rs b/seaweed-volume/src/storage/store.rs index 8f99ebb3d..7bb3d6890 100644 --- a/seaweed-volume/src/storage/store.rs +++ b/seaweed-volume/src/storage/store.rs @@ -130,21 +130,29 @@ impl Store { // ---- Volume lifecycle ---- /// Find the location with fewest volumes (load-balance) of the given disk type. + /// Matches Go's FindFreeLocation: accounts for EC shards when computing free slots. fn find_free_location(&self, disk_type: &DiskType) -> Option { - let mut best: Option<(usize, usize)> = None; // (index, volume_count) + use crate::storage::erasure_coding::ec_shard::DATA_SHARDS_COUNT; + + let mut best: Option<(usize, i64)> = None; // (index, effective_free) for (i, loc) in self.locations.iter().enumerate() { if &loc.disk_type != disk_type { continue; } - if loc.free_volume_count() <= 0 { + // Go formula: currentFreeCount = (MaxVolumeCount - VolumesLen()) * DataShardsCount - EcShardCount() + // currentFreeCount /= DataShardsCount + let max = loc.max_volume_count.load(Ordering::Relaxed) as i64; + let free_count = (max - loc.volumes_len() as i64) * DATA_SHARDS_COUNT as i64 + - loc.ec_shard_count() as i64; + let effective_free = free_count / DATA_SHARDS_COUNT as i64; + if effective_free <= 0 { continue; } if loc.is_disk_space_low.load(Ordering::Relaxed) { continue; } - let count = loc.volumes_len(); - if best.is_none() || count < best.unwrap().1 { - best = Some((i, count)); + if best.is_none() || effective_free > best.unwrap().1 { + best = Some((i, effective_free)); } } best.map(|(i, _)| i)