Skip to content

Avoid per-entry Windows metadata queries - #359

Merged
Byron merged 6 commits into
mainfrom
windows-performance
Aug 3, 2026
Merged

Avoid per-entry Windows metadata queries#359
Byron merged 6 commits into
mainfrom
windows-performance

Conversation

@Byron

@Byron Byron commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Tasks

This section is for Byron only. Models continuing this PR must not add, remove, check, uncheck, rename, or reorder checkboxes here.

  • quick review, mostly windows only changes, and integration into existing walk.

Everything below this line was generated by Codex.

Created by Codex on behalf of Byron. Byron will review before this is ready to merge.

Fixes #302

Reported issue

On Windows, the parallel walker should obtain metadata directly from directory enumeration, following the optimization used by the local gix-status/src/fscache.rs, and avoid per-entry stat-like path queries.

Behavioral summary

Both public and internal walks now consume FILE_ID_BOTH_DIR_INFO records directly on Windows. Each record supplies logical size, allocation size, modification time, file type, reparse tag, and file ID without reconstructing the path or issuing a metadata call for that entry.

  • Default disk usage uses the enumerated allocation size for files and preserves zero-sized directory accounting.
  • --apparent-size uses the enumerated end-of-file value.
  • Hard-link filtering uses the enumerated volume/file ID.
  • Name-surrogate reparse points remain non-directories and explicitly supplied root symlinks/junctions are opened without following them.
  • Raw enumeration failures are reported as I/O errors; there is no slow path-based fallback.
  • Windows now exposes its native entry, file-type, and metadata types as WalkEntry, WalkFileType, and WalkMetadata; this intentionally changes the platform's public concrete types while retaining the commonly used path, is_dir, is_file, is_symlink, len, and modified operations.
  • Non-Windows platforms retain their existing std::fs entry metadata path.

Performance

Measured from this worktree by alternating three release runs of dua ../ for each build:

Build Median Runs
Current main 27.93 s 27.93, 28.16, 26.91 s
This branch 0.81 s 0.81, 0.89, 0.80 s

The branch is about 34.5× faster than main on this scan.

Implementation

  • Add a narrowly scoped Windows raw-directory backend around GetFileInformationByHandleEx(FileIdBothDirectoryInfo) with a 64 KiB aligned buffer.
  • Use one concrete walker entry type per target; remove the marker trait, generic worker pool, reader dispatch table, and duplicate std::fs Windows reader.
  • Keep Windows directory enumeration, metadata, and entry details isolated in walk/windows.rs.
  • Stream completion-order records in bounded batches and schedule accepted child directories across the existing worker pool.
  • Validate record bounds and unaligned UTF-16 names, preserve reparse semantics, and close owned handles reliably.
  • Keep filesize only on non-Windows targets because Windows no longer calls it.
  • The simplification patch removes 110 net lines; the complete PR is now 846 additions and 45 deletions.

Validation

  • cargo +nightly check --all-targets
  • cargo +nightly test --all (94 tests passed)
  • cargo +nightly fmt --all -- --check
  • cargo +nightly clippy -- -D warnings
  • cargo +nightly doc --no-deps
  • Linux target: Clippy plus all-features and no-default-features checks, including tui-crossplatform and trash-move.
  • Windows regressions cover enumerated sizes and IDs, hard links, 64 KiB buffer refills, reparse tags, removed paths, zero-sized directories, root directory symlinks, and the public file-type predicates.
  • Committed-hash reviews: 6cff20884079bdf9c0ea86f069cc48167f05675f, c9166c23080798c8158ca7208da50d8baf8088e3, 352af73aa259032624c854dbf3a8ca22e1bd949c, df631a9cf3d32b8b63c9db65c959ac41fead5aed, and f7276b7b4903427d5c20db7fdaf1b72e6440a90e.

@Byron Byron changed the title Optimize Windows directory metadata scheduling Avoid per-entry Windows metadata queries Aug 3, 2026
codex added 5 commits August 3, 2026 11:18
Windows directory iteration already returns entry metadata without another
system call, but completion-order traversal split every listing into small
stat jobs and handed those entries across worker queues. A wide-directory
regression demonstrated that eight workers redundantly participated in
metadata conversion for one Windows directory.

Convert Windows entries on the worker enumerating their parent and schedule
only accepted child-directory reads for parallel work. Retain stealable stat
batches on other platforms, where DirEntry::metadata may issue a separate
symlink-metadata call. This follows the gix-status filesystem cache baseline,
which likewise consumes metadata returned by Windows directory enumeration
instead of issuing per-path metadata queries.

Validated with the focused Windows scheduling regression, cargo +nightly
check --all --bins --tests --examples, cargo +nightly test --all, formatting,
and a Linux-target clippy build. The generic Windows clippy command still
reports pre-existing warnings in crossdev.rs and inodefilter.rs; Linux clippy
likewise reaches a pre-existing warning in interactive/app/common.rs.
Read FILE_ID_BOTH_DIR_INFO records directly for internal Windows walks so
logical size, allocated size, modification time, file type, and file ID
arrive with directory enumeration. Keep the public WalkEntry API unchanged
and report enumeration failures instead of falling back to path-based stats.

On this worktree, default 'dua ..' drops from about 25.9 seconds to
0.86 seconds while preserving hard-link and reparse-point handling.
Keep the Windows nightly clippy job passing with the current lint set.
Factor the non-Windows stat-reader function pointer into a type alias so the Linux Clippy job accepts the platform-specific pool abstraction.
Use one concrete entry type per target instead of carrying a generic pool,
reader dispatch table, and a marker trait through the traversal engine.
On Windows the native directory entry becomes the public walk entry, so
both public and internal traversal use the metadata returned by directory
enumeration.

This removes the duplicate std::fs Windows reader and keeps the Windows
implementation isolated in walk/windows.rs.
@Byron
Byron force-pushed the windows-performance branch from f7276b7 to f94fe6d Compare August 3, 2026 09:19
@Byron
Byron marked this pull request as ready for review August 3, 2026 09:45
@Byron
Byron merged commit bdee013 into main Aug 3, 2026
2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d784e024a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/walk/windows.rs
@Byron
Byron deleted the windows-performance branch August 3, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slow scanning on Windows with big folder (compare to other tools such as TreeSize free)

2 participants