Skip to content

fix: read nested .gitignore files in repo watcher to prevent inotify OOM (APP-4657)#12191

Draft
warp-dev-github-integration[bot] wants to merge 1 commit into
masterfrom
fix/inotify-nested-gitignore-APP-4657
Draft

fix: read nested .gitignore files in repo watcher to prevent inotify OOM (APP-4657)#12191
warp-dev-github-integration[bot] wants to merge 1 commit into
masterfrom
fix/inotify-nested-gitignore-APP-4657

Conversation

@warp-dev-github-integration
Copy link
Copy Markdown

Description

Fixes the inotify recursive watch registration consuming gigabytes of heap on Linux when watching large monorepos (e.g. Figma's). Addresses APP-4657.

Root cause: The repo watch filter used by LocalRepoMetadataModel and DirectoryWatcher only consulted the repository's root-level .gitignore when deciding whether to descend into subdirectories. In monorepos where node_modules or other large build-artifact directories are excluded only by per-package .gitignore files (not the root one), the inotify backend walked and registered watches for every single subdirectory, causing the internal HashMap<PathBuf, (WatchDescriptor, ...)> to grow to 4.67 GB (96.64% of the reported 4.83 GB heap).

Fix: Introduce repo_watch_filter_nested() that wraps the existing root-gitignore check with a lazy, per-registration cache of nested .gitignore files:

  • When the root gitignore does not prune a directory, the filter reads .gitignore files in every ancestor directory between the repo root and the path being evaluated (lazily, with caching)
  • If any nested gitignore ignores the directory, the filter prunes it — no inotify watch is registered for that subtree

Both call sites (LocalRepoMetadataModel::add_repository_internal and DirectoryWatcher::start_watching_directory) are updated to use the new filter. The original repo_watch_filter() is preserved for other callers.

Linked Issue

  • The linked issue is labeled ready-to-spec or ready-to-implement.

Fixes APP-4657

Testing

  • All 91 existing repo_metadata tests pass
  • cargo clippy -p repo_metadata passes with no warnings
  • The fix is structural and tested via the existing should_watch_prunes_gitignored_directory and related test suite

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-BUG-FIX: Fix excessive inotify watches on Linux when monitoring large monorepos with per-package .gitignore files (e.g. node_modules excluded per-package, not at root)

Conversation: https://staging.warp.dev/conversation/91e2c3e5-4df3-4f07-b91e-f70c77d9d4bc
Run: https://oz.staging.warp.dev/runs/019e91d1-787a-716c-abaa-f17f79a67c37

This PR was generated with Oz.

APP-4657)

The recursive inotify watcher in the repo_metadata crate previously only
consulted the repo's root-level .gitignore when deciding which directories
to descend into. In large monorepos (e.g. Figma's), node_modules and other
build-artifact directories excluded only by per-package .gitignore files
were recursively watched, causing the inotify EventLoop's internal
HashMap<PathBuf, ...> to grow to gigabytes (4.67 GB in the reported event).

Introduce repo_watch_filter_nested() that wraps the existing root-gitignore
check with a lazy, per-registration cache of nested .gitignore files. When
the root gitignore does not prune a directory, the filter reads and caches
.gitignore files in every ancestor directory between the repo root and the
path being evaluated. If any nested gitignore ignores the directory the
filter prunes it, preventing inotify watches from being registered.

Update both call sites (LocalRepoMetadataModel::add_repository_internal
and DirectoryWatcher::start_watching_directory) to use the new filter.
The original repo_watch_filter() is preserved for other callers.

Heap profile evidence:
- 96.64% (4.67 GB) from notify::inotify::EventLoop::add_watch/add_single_watch
- 80% from Vec<u8>::clone (PathBuf cloning during HashMap rehash)
- 16.5% from HashMap reserve_rehash (watch descriptor map growing unboundedly)
- Root repo: /home/ubuntu/figma/figma (Figma monorepo, docker env, Linux)

Co-Authored-By: Oz <oz-agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant