Skip to content

fix(file_watcher): unbounded pending HashMap causes OOM and O(n³) debounce under mass file events #163

Description

@bug-ops

Description

The debounce loop in file_watcher.rs accumulates all pending events in an unbounded HashMap. Under git checkout of a large branch or bulk file generation, tens of thousands of events can arrive before the 100 ms debounce window closes. compute_changes then iterates all pending entries against all LSP registration globs at O(pending × registrations × patterns).

Additionally, NEVER_FORWARD_COMPONENTS excludes .git and target but not vendor/, third_party/, node_modules/, or other large dependency trees, so projects using those layouts can trigger the pathological case.

Reproduction Steps

  1. Configure mcpls for a large monorepo with vendor/ directory
  2. Run git checkout switching to a branch with significant vendored changes
  3. Observe: memory spike during the 100 ms debounce window; potential multi-second stall in compute_changes

Expected Behavior

The watcher should shed excess events gracefully rather than buffering without limit.

Actual Behavior

pending HashMap grows without bound until the debounce fires.

Affected Code

  • crates/mcpls-core/src/lsp/file_watcher.rs — debounce accumulator, line ~352
  • NEVER_FORWARD_COMPONENTS filter list

Fix Direction

  1. Cap pending at a reasonable limit (e.g. 10 000 entries); on overflow, emit a single synthetic "invalidate all" event rather than tracking individual paths.
  2. Extend NEVER_FORWARD_COMPONENTS to include vendor, node_modules, third_party.

Environment

  • Affects large monorepos or projects with vendored dependencies
  • Severity: low for typical projects, high for monorepos

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low: cosmetic, edge case unlikely in practicebugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions