From ab694859ca1ac8e6a0fdbc22149b39faa721bdc6 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 10:27:11 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=20entry.path().is?= =?UTF-8?q?=5Ffile()=20with=20entry.file=5Ftype().is=5Ffile()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces calls to `entry.path().is_file()` during `ignore::WalkBuilder` traversal with `entry.file_type().is_some_and(|ft| ft.is_file())` in several core components (`file_service/rename`, `checksums`, `directory_rename`, and `prune_ops`). The former executes an unnecessary `stat` syscall for every file, creating an I/O bottleneck on large directory walks. The latter leverages metadata pre-fetched natively by `readdir` avoiding the redundant lookup altogether. Co-authored-by: mudcube <101564+mudcube@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ crates/mill-handlers/src/handlers/common/checksums.rs | 3 ++- crates/mill-handlers/src/handlers/prune_ops.rs | 3 ++- .../mill-handlers/src/handlers/rename_ops/directory_rename.rs | 3 ++- .../src/services/filesystem/file_service/rename.rs | 3 ++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 541c0ab51..28b6d5894 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -17,3 +17,7 @@ ## 2025-05-19 - File Discovery Allocations **Learning:** In `discover_importing_files`, `WalkBuilder` results were being converted to `PathBuf` via `.map(|e| e.into_path())` *before* filtering. This caused allocations for every single file in the workspace (including excluded files and directories). **Action:** Filter `ignore::DirEntry` directly using `entry.file_type()` and `entry.path()` before mapping to `PathBuf`. This avoids allocations for non-matching files. + +## 2024-06-06 - Directory Traversal Stat Syscalls +**Learning:** Calling `entry.path().is_file()` on `ignore::DirEntry` triggers an unnecessary `stat` syscall for every entry, becoming a bottleneck during directory traversals. +**Action:** Always use `entry.file_type().is_some_and(|ft| ft.is_file())` instead to reuse metadata from `readdir`. diff --git a/crates/mill-handlers/src/handlers/common/checksums.rs b/crates/mill-handlers/src/handlers/common/checksums.rs index 79a48a327..b39ac7d6d 100644 --- a/crates/mill-handlers/src/handlers/common/checksums.rs +++ b/crates/mill-handlers/src/handlers/common/checksums.rs @@ -79,7 +79,8 @@ pub async fn calculate_checksums_for_directory_rename( .build(); for entry in walker.flatten() { - if entry.path().is_file() { + // Use file_type() to avoid unnecessary stat syscalls + if entry.file_type().is_some_and(|ft| ft.is_file()) { if let Ok(content) = context.app_state.file_service.read_file(entry.path()).await { file_checksums.insert( entry.path().to_string_lossy().to_string(), diff --git a/crates/mill-handlers/src/handlers/prune_ops.rs b/crates/mill-handlers/src/handlers/prune_ops.rs index 2f9ca3a91..a07afbffc 100644 --- a/crates/mill-handlers/src/handlers/prune_ops.rs +++ b/crates/mill-handlers/src/handlers/prune_ops.rs @@ -665,7 +665,8 @@ impl PrunePlanner { let walker = ignore::WalkBuilder::new(&abs_dir).hidden(false).build(); let files = walker .flatten() - .filter(|entry| entry.path().is_file()) + // Use file_type() to avoid unnecessary stat syscalls + .filter(|entry| entry.file_type().is_some_and(|ft| ft.is_file())) .map(|entry| entry.path().to_path_buf()) .collect(); Ok((files, abs_dir)) diff --git a/crates/mill-handlers/src/handlers/rename_ops/directory_rename.rs b/crates/mill-handlers/src/handlers/rename_ops/directory_rename.rs index 68aead607..f7b4030e6 100644 --- a/crates/mill-handlers/src/handlers/rename_ops/directory_rename.rs +++ b/crates/mill-handlers/src/handlers/rename_ops/directory_rename.rs @@ -287,7 +287,8 @@ impl RenameService { let mut files_to_move = 0; let walker = ignore::WalkBuilder::new(&old_path).hidden(false).build(); for entry in walker.flatten() { - if entry.path().is_file() { + // Use file_type() to avoid unnecessary stat syscalls + if entry.file_type().is_some_and(|ft| ft.is_file()) { files_to_move += 1; } } diff --git a/crates/mill-services/src/services/filesystem/file_service/rename.rs b/crates/mill-services/src/services/filesystem/file_service/rename.rs index b8b364ffa..e3e4b6536 100644 --- a/crates/mill-services/src/services/filesystem/file_service/rename.rs +++ b/crates/mill-services/src/services/filesystem/file_service/rename.rs @@ -469,7 +469,8 @@ impl FileService { let mut files = Vec::new(); let walker = ignore::WalkBuilder::new(dir).hidden(false).build(); for entry in walker.flatten() { - if entry.path().is_file() { + // Use file_type() to avoid unnecessary stat syscalls + if entry.file_type().is_some_and(|ft| ft.is_file()) { files.push(entry.path().to_path_buf()); } }