Fix walked_roots to only include recursively walked directories

This commit is contained in:
Joe 2026-03-06 20:53:28 -06:00
parent 4e9e676cf2
commit dc788711c7
3 changed files with 27 additions and 4 deletions

View file

@ -50,6 +50,11 @@ pub struct PrefetchCache {
/// Populated during prefetch so that `get_dir_middleware` can skip
/// per-file VFS metadata probes entirely.
pub dir_init: HashMap<PathBuf, Option<(String, PathBuf)>>,
/// Directories that were recursively walked during prefetch. A metadata
/// cache miss is only treated as NotFound if the queried path falls
/// under one of these roots. Paths outside walked roots fall through
/// to the backend (they may exist but weren't covered by the walk).
pub walked_roots: Vec<PathBuf>,
}
mod sealed {
@ -288,11 +293,17 @@ impl VfsInner {
if let Some(&is_file) = cache.is_file.get(path) {
return Ok(Metadata { is_file });
}
if cache
.walked_roots
.iter()
.any(|root| path.starts_with(root))
{
return Err(io::Error::new(
io::ErrorKind::NotFound,
"not in prefetch cache",
));
}
}
self.backend.metadata(path)
}
@ -754,6 +765,7 @@ mod test {
is_file: HashMap::new(),
children: HashMap::new(),
dir_init: HashMap::new(),
walked_roots: Vec::new(),
}
}
@ -891,6 +903,7 @@ mod test {
is_file: HashMap::new(),
children: HashMap::new(),
dir_init: HashMap::new(),
walked_roots: Vec::new(),
});
let result = vfs.read(&file_path).unwrap();
@ -937,6 +950,7 @@ mod test {
is_file: HashMap::new(),
children: HashMap::new(),
dir_init: HashMap::new(),
walked_roots: Vec::new(),
});
let handles: Vec<_> = (0..100)
@ -978,6 +992,7 @@ mod test {
is_file: HashMap::new(),
children: HashMap::new(),
dir_init: HashMap::new(),
walked_roots: Vec::new(),
});
for i in 0..50 {

View file

@ -156,6 +156,7 @@ fn prefetch_project_files(project: &Project, sync_scripts_only: bool) -> io::Res
is_file: HashMap::new(),
children: HashMap::new(),
dir_init: HashMap::new(),
walked_roots: Vec::new(),
});
}
@ -181,11 +182,15 @@ fn prefetch_project_files(project: &Project, sync_scripts_only: bool) -> io::Res
// Recursive walk of each $path root. Canonicalize to resolve ".."
// before the equality/starts_with checks.
let canonical_folder = std::fs::canonicalize(folder).unwrap_or_else(|_| folder.to_path_buf());
let mut walked_roots: Vec<PathBuf> = Vec::new();
for root in &roots {
if !root.exists() {
continue;
}
let canonical_root = std::fs::canonicalize(root).unwrap_or_else(|_| root.to_path_buf());
if canonical_root != canonical_folder {
walked_roots.push(canonical_root.clone());
}
if canonical_root == canonical_folder {
// $path points to the project folder itself -- shallow walk
// already covers depth 0-1, fill in the subtree.
@ -286,6 +291,7 @@ fn prefetch_project_files(project: &Project, sync_scripts_only: bool) -> io::Res
is_file: is_file_map,
children: children_map,
dir_init: dir_init_map,
walked_roots,
})
}

View file

@ -269,6 +269,7 @@ fn parallel_snapshot_with_prefetch_cache() {
is_file,
children: children_map,
dir_init: std::collections::HashMap::new(),
walked_roots: Vec::new(),
});
let snap_cached = librojo::snapshot_from_vfs(&ctx, &vfs_cached, &project_path)
@ -375,6 +376,7 @@ fn overlapping_path_roots_no_duplicate_children() {
is_file,
children: children_map,
dir_init: std::collections::HashMap::new(),
walked_roots: Vec::new(),
});
let snap = librojo::snapshot_from_vfs(&ctx, &vfs, &project_path)