Skip to content

Commit bae8edf

Browse files
committed
Skip stale fs store artifacts
The exhaustive filesystem store listing treated leftover temp and trash files as namespace directories after identifying them as non-keys. Skip those artifacts before recursing so migrations can ignore crash leftovers.
1 parent 3d94ac7 commit bae8edf

2 files changed

Lines changed: 37 additions & 12 deletions

File tree

lightning-persister/src/fs_store/common.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ impl FilesystemStoreState {
653653
'primary_loop: for primary_entry in fs::read_dir(prefixed_dest)? {
654654
let primary_entry = primary_entry?;
655655
let primary_path = primary_entry.path();
656+
if dir_entry_is_store_artifact(&primary_path) {
657+
continue 'primary_loop;
658+
}
656659

657660
if dir_entry_is_key(&primary_entry)? {
658661
let primary_namespace = String::new();
@@ -666,6 +669,9 @@ impl FilesystemStoreState {
666669
'secondary_loop: for secondary_entry in fs::read_dir(&primary_path)? {
667670
let secondary_entry = secondary_entry?;
668671
let secondary_path = secondary_entry.path();
672+
if dir_entry_is_store_artifact(&secondary_path) {
673+
continue 'secondary_loop;
674+
}
669675

670676
if dir_entry_is_key(&secondary_entry)? {
671677
let primary_namespace = get_key_from_dir_entry_path(
@@ -683,6 +689,9 @@ impl FilesystemStoreState {
683689
for tertiary_entry in fs::read_dir(&secondary_path)? {
684690
let tertiary_entry = tertiary_entry?;
685691
let tertiary_path = tertiary_entry.path();
692+
if dir_entry_is_store_artifact(&tertiary_path) {
693+
continue;
694+
}
686695

687696
if dir_entry_is_key(&tertiary_entry)? {
688697
let primary_namespace = get_key_from_dir_entry_path(
@@ -720,20 +729,14 @@ impl FilesystemStoreState {
720729
}
721730
}
722731

732+
fn dir_entry_is_store_artifact(path: &Path) -> bool {
733+
path.extension().and_then(|ext| ext.to_str()).is_some_and(|ext| ext == "tmp" || ext == "trash")
734+
}
735+
723736
pub(crate) fn dir_entry_is_key(dir_entry: &fs::DirEntry) -> Result<bool, lightning::io::Error> {
724737
let p = dir_entry.path();
725-
if let Some(ext) = p.extension() {
726-
#[cfg(target_os = "windows")]
727-
{
728-
// Clean up any trash files lying around.
729-
if ext == "trash" {
730-
fs::remove_file(p).ok();
731-
return Ok(false);
732-
}
733-
}
734-
if ext == "tmp" {
735-
return Ok(false);
736-
}
738+
if dir_entry_is_store_artifact(&p) {
739+
return Ok(false);
737740
}
738741

739742
let file_type = dir_entry.file_type()?;

lightning-persister/src/fs_store/v1.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,28 @@ mod tests {
186186
assert_eq!(listed_keys.len(), 0);
187187
}
188188

189+
#[test]
190+
fn list_all_keys_skips_leftover_store_artifacts() {
191+
let mut temp_path = std::env::temp_dir();
192+
temp_path.push("test_list_all_keys_skips_leftover_store_artifacts");
193+
let fs_store = FilesystemStore::new(temp_path.clone());
194+
KVStoreSync::write(&fs_store, "primary", "secondary", "key", vec![1]).unwrap();
195+
196+
fs::write(temp_path.join("top_level.0.tmp"), b"stale").unwrap();
197+
fs::write(temp_path.join("top_level.0.trash"), b"stale").unwrap();
198+
199+
let primary_path = temp_path.join("primary");
200+
fs::write(primary_path.join("primary_level.0.tmp"), b"stale").unwrap();
201+
fs::write(primary_path.join("primary_level.0.trash"), b"stale").unwrap();
202+
203+
let secondary_path = primary_path.join("secondary");
204+
fs::write(secondary_path.join("secondary_level.0.tmp"), b"stale").unwrap();
205+
fs::write(secondary_path.join("secondary_level.0.trash"), b"stale").unwrap();
206+
207+
let keys = fs_store.list_all_keys().unwrap();
208+
assert_eq!(keys, vec![("primary".to_string(), "secondary".to_string(), "key".to_string())]);
209+
}
210+
189211
#[test]
190212
fn test_data_migration() {
191213
let mut source_temp_path = std::env::temp_dir();

0 commit comments

Comments
 (0)