Skip to content

engine: parallel directory traversal + --sort modes + -j (#43) - #140

Merged
helly25 merged 2 commits into
mainfrom
feat/parallel-walk
Jun 27, 2026
Merged

engine: parallel directory traversal + --sort modes + -j (#43)#140
helly25 merged 2 commits into
mainfrom
feat/parallel-walk

Conversation

@helly25

@helly25 helly25 commented Jun 27, 2026

Copy link
Copy Markdown
Owner

The flagship parallel traversal (#43), built to docs/design-parallel.md. Single PR covering the worker pool + all four --sort modes + -j + the TSan cell, per request.

What's in it

  • Worker pool (ReadPool) runs readdir+lstat off the coordinator thread. Jobs are pure (path -> stat'd listing) and touch only the thread-safe vfs::FileSystem and a mutex-guarded queue. The visitor stays single-threaded on the coordinator in --sort order, so evaluate/emit/exec/capture/summary are unchanged and race-free (run.cc untouched).
  • --sort=none|dir|subtree|tree (name aliases dir): none = readdir order; dir = each directory's sorted listing block then its subtrees; subtree = sorted non-dir entries then contiguous subtrees; tree = total path order. Ordered modes are deterministic (siblings consumed sorted while the pool prefetches their reads).
  • -j N / --jobs=N sets the worker count (default 1 = sequential walk). The parent batches its subdirectories' reads so the pool overlaps their IO; each directory is read exactly once.
  • TSan: --config=tsan in .bazelrc + a ubuntu-only, repo-cache-only clang-tsan CI job wired into done (no multi-GB disk cache, so the 10 GB Actions budget stays healthy beside the asan caches).

Tests

  • walk_test: parallel set-equality (workers=8) and deterministic ordering for all three ordered modes at workers=1 and 4.
  • Full suite green under default, --config=clang --config=asan (asan+ubsan), and --config=clang --config=tsan (no data races).
  • Verified end-to-end via the CLI (--sort=tree/dir/subtree, --jobs=4, -j2).

Deferred (follow-ups, noted in the design doc)

helly25 added 2 commits June 27, 2026 12:35
Add a bounded worker pool (ReadPool) that runs readdir+lstat off the
coordinator thread; the visitor still runs single-threaded in --sort order,
so evaluate/emit/exec/capture/summary stay unchanged and race-free. Workers
are pure (path -> stat'd listing), touching only the thread-safe VFS and a
mutex-guarded queue.

--sort grows to none|dir|subtree|tree (name aliases dir): none = readdir
order; dir = each directory's sorted listing block then its subtrees; subtree
= sorted non-dir entries then contiguous subtrees; tree = total path order.
The ordered modes are deterministic (siblings consumed in sorted order while
the pool prefetches their reads). -j N / --jobs=N sets the worker count
(default 1 = sequential); the parent batches subdirectory reads so the pool
overlaps their IO.

Adds --config=tsan and a ubuntu-only, repo-cache-only clang-tsan CI cell
(kept off the disk cache so the 10 GB Actions budget stays healthy next to
asan). walk_test covers parallel set-equality and deterministic ordering for
all modes at workers=1 and 4; full suite is green under asan+ubsan and tsan.

Deferred (follow-ups): mode-scoped auto-defaults (modern -> parallel+dir) with
the mode mechanism (#54); completion-order subtree streaming; per-worker eval.
Record the three deliberate v1 simplifications: IO-only parallelism with a
single-threaded visitor, deterministic (sorted) ordered modes, and opt-in
-j/--sort with mode-scoped auto-defaults deferred to the mode mechanism (#54).
@helly25
helly25 enabled auto-merge (squash) June 27, 2026 11:37
@helly25
helly25 merged commit 78b8beb into main Jun 27, 2026
8 checks passed
@helly25
helly25 deleted the feat/parallel-walk branch June 27, 2026 11:45
helly25 added a commit that referenced this pull request Jun 27, 2026
…g = StatusOr (#141)

Follow-up to #140 addressing review feedback:
- Listing was a hand-rolled StatusOr (vector + status with an implicit
  not-ok-means-empty invariant); make it absl::StatusOr<std::vector<Stated>>,
  matching ReadDir/Stat everywhere else.
- ReadPool now uses absl::Mutex with full thread-safety annotations:
  queue_/stop_ are ABSL_GUARDED_BY(mutex_); the wait predicate Pending() is
  ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); Submit/Run are ABSL_LOCKS_EXCLUDED.
  absl::Mutex::Await replaces the condition_variable (a job becoming ready or
  stop_ wakes waiters on unlock), so there is no separate signal to forget.

Builds clean under -Wthread-safety; full suite green under default, asan+ubsan,
and tsan.
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.

1 participant