mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-22 07:06:51 +00:00
fix(ec): remove a stale .vif on full teardown of a shard-only node
A shard copy installs shards + .ecx before .vif, so an interrupted copy after a teardown could mount the new files under the previous run's identity / version / shard ratio / dat_file_size carried by the surviving .vif. Remove .vif during full teardown, gated on .idx absence so a source-volume holder keeps its live .vif. In Rust this lives in a teardown-only helper so the reconcile / load- fallback paths (which share the base removal) still preserve .vif.
This commit is contained in:
@@ -2609,7 +2609,7 @@ impl VolumeServer for VolumeGrpcService {
|
||||
let mut store = self.state.store.write().unwrap();
|
||||
let _ = store.remove_ec_volume(vid);
|
||||
for loc in &store.locations {
|
||||
loc.remove_ec_volume_files(&req.collection, vid);
|
||||
loc.remove_ec_volume_files_full_teardown(&req.collection, vid);
|
||||
}
|
||||
}
|
||||
self.state.volume_state_notify.notify_one();
|
||||
|
||||
@@ -328,6 +328,28 @@ impl DiskLocation {
|
||||
}
|
||||
}
|
||||
|
||||
/// Full-teardown variant: everything remove_ec_volume_files clears, PLUS the
|
||||
/// normal-volume <base>.vif on a SHARD-ONLY node. An interrupted shard copy
|
||||
/// (which installs shards + .ecx before .vif) could otherwise mount a fresh
|
||||
/// generation under the prior run's identity / ratio / dat_file_size carried by
|
||||
/// a stale .vif. Gated on .idx absence so a source-volume holder keeps its live
|
||||
/// .vif. Reconcile/load-fallback call remove_ec_volume_files directly and
|
||||
/// intentionally preserve it, mirroring Go's removeEcVolumeFiles (reconcile) vs
|
||||
/// removeStaleEcArtifacts (teardown) split.
|
||||
pub(crate) fn remove_ec_volume_files_full_teardown(&self, collection: &str, vid: VolumeId) {
|
||||
self.remove_ec_volume_files(collection, vid);
|
||||
let base = volume_file_name(&self.directory, collection, vid);
|
||||
let idx_base = volume_file_name(&self.idx_directory, collection, vid);
|
||||
if !std::path::Path::new(&format!("{}.idx", idx_base)).exists() {
|
||||
let _ = fs::remove_file(format!("{}.vif", idx_base));
|
||||
if self.idx_directory != self.directory
|
||||
&& !std::path::Path::new(&format!("{}.idx", base)).exists()
|
||||
{
|
||||
let _ = fs::remove_file(format!("{}.vif", base));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a volume by ID.
|
||||
pub fn find_volume(&self, vid: VolumeId) -> Option<&Volume> {
|
||||
self.volumes.get(&vid)
|
||||
|
||||
@@ -557,6 +557,21 @@ func removeStaleEcArtifacts(dataBaseFileName, indexBaseFileName string, total in
|
||||
record(removeFileIfExists(dataBaseFileName + ".ecj"))
|
||||
record(removeBitrotSidecars(dataBaseFileName))
|
||||
}
|
||||
|
||||
// Canonical <base>.vif. A shard copy installs shards + .ecx before .vif, so an
|
||||
// interrupted copy can leave a stale .vif whose run identity / shard ratio /
|
||||
// dat_file_size a fresh generation would inherit. Remove it only on a shard-only
|
||||
// EC node: where a normal <base>.idx exists this is the source volume holder and
|
||||
// the .vif belongs to that live volume — keep it. This mirrors the !hasIdxFile
|
||||
// gate in the per-shard delete path.
|
||||
if _, statErr := os.Stat(indexBaseFileName + ".idx"); os.IsNotExist(statErr) {
|
||||
record(removeFileIfExists(indexBaseFileName + ".vif"))
|
||||
if dataBaseFileName != indexBaseFileName {
|
||||
if _, dStatErr := os.Stat(dataBaseFileName + ".idx"); os.IsNotExist(dStatErr) {
|
||||
record(removeFileIfExists(dataBaseFileName + ".vif"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return firstErr
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user