From 24895a39623d1101da4ec42b12075d53753ee111 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 9 Mar 2026 06:19:40 -0700 Subject: [PATCH] fix: EC shard copy address parsing and preserve .vif on volume destroy Two bugs found during EC encoding + balancing test with 4 Rust volume servers: 1. VolumeEcShardsCopy manually split source_data_node on '.' which broke on IP addresses with dots. Now uses parse_grpc_address() like other RPCs. 2. remove_volume_files() deleted .vif files, breaking EC volumes that need the .vif after the original volume is destroyed. Matches Go's Destroy() which only removes .dat/.idx. --- seaweed-volume/src/server/grpc_server.rs | 22 ++++++---------------- seaweed-volume/src/storage/volume.rs | 5 ++++- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/seaweed-volume/src/server/grpc_server.rs b/seaweed-volume/src/server/grpc_server.rs index b3582d809..660944974 100644 --- a/seaweed-volume/src/server/grpc_server.rs +++ b/seaweed-volume/src/server/grpc_server.rs @@ -1814,22 +1814,12 @@ impl VolumeServer for VolumeGrpcService { // Connect to source and copy shard files via CopyFile let source = &req.source_data_node; - // Parse source address: "ip:port.grpc_port" - let parts: Vec<&str> = source.split('.').collect(); - if parts.len() != 2 { - return Err(Status::internal(format!( - "VolumeEcShardsCopy volume {} invalid source_data_node {}", - vid, source - ))); - } - let grpc_addr = format!( - "{}:{}", - parts[0] - .rsplit_once(':') - .map(|(h, _)| h) - .unwrap_or(parts[0]), - parts[1] - ); + let grpc_addr = parse_grpc_address(source).map_err(|e| { + Status::internal(format!( + "VolumeEcShardsCopy volume {} invalid source_data_node {}: {}", + vid, source, e + )) + })?; let channel = tonic::transport::Channel::from_shared(format!("http://{}", grpc_addr)) .map_err(|e| { diff --git a/seaweed-volume/src/storage/volume.rs b/seaweed-volume/src/storage/volume.rs index b06a1d6ce..579094584 100644 --- a/seaweed-volume/src/storage/volume.rs +++ b/seaweed-volume/src/storage/volume.rs @@ -2167,7 +2167,10 @@ fn get_append_at_ns(last: u64) -> u64 { /// Remove all files associated with a volume. pub(crate) fn remove_volume_files(base: &str) { - for ext in &[".dat", ".idx", ".vif", ".sdx", ".cpd", ".cpx", ".note", ".rdb"] { + // Note: .vif is intentionally NOT deleted here — it must be preserved + // for EC volumes that reference it after the original volume is destroyed. + // Matches Go's volume.Destroy() which only removes .dat/.idx. + for ext in &[".dat", ".idx", ".sdx", ".cpd", ".cpx", ".note", ".rdb"] { let _ = fs::remove_file(format!("{}{}", base, ext)); } // leveldb uses a directory