Skip to content

fix(pipeline): sequential definitions pass caches every result with its parse tree and working arena #2416

Closed

Description

@Fieldnote-Echo

Version

built from source, main @ 2278498 (v0.11.0-186)

Platform

Linux (x64)

Install channel

Built from source

Binary variant

standard

What happened, and what did you expect?

On the sequential route, which a repo takes with 50 files or fewer or with CBM_WORKERS=1 (src/pipeline/pipeline.c:2684), cbm_pipeline_pass_definitions caches each file's raw result (pass_definitions.c:870-871) with its tree-sitter tree and uncompacted working arena until the run ends. The parallel worker frees the tree (pass_parallel.c:1233) and compacts the result (pass_parallel.c:1290) before caching. So peak memory on the sequential route grows by about 1.7 MB per small Python file instead of about 0.2 MB, and a small repo of large files takes this route at any worker count.

The fix frees the tree and compacts the result before caching, as the parallel worker does, and releases the thread's working arena when the pass ends. The graph is byte-identical on 7 sequential-route corpora. The cost is that the cross-file LSP pass re-parses these files, as it already does on the parallel route (268-275 ms to 528 ms on the 480-file corpus).

Reproduction

To see it, index 40 large .py files with default settings (I used 17.9 MiB from torch, tensorflow, scipy, wx and others), or any Python tree with CBM_WORKERS=1, and watch peak memory.

Peak memory, Linux x86_64, 32 logical CPUs, GCC 16 main fixed
40 large .py files, 3 workers (sequential because ≤ 50 files) 962 MB 246 MB
480 .py files from a Python 3.14 install, CBM_WORKERS=1 865 MB 137 MB
240 .go files from the Go 1.26.3 source, CBM_WORKERS=1 225 MB 108 MB

Logs


Diagnostics trajectory (memory / performance / leak issues)

Not a leak: the extra memory is held until one index run ends, so the table gives each run's peak memory rather than a trajectory.

Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

  1. added
    stability/performanceServer crashes, OOM, hangs, high CPU/memory
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Oct 1, 2026
  2. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you for separating retained per-run memory from a leak and for including the reparse-time tradeoff. The sequential-versus-parallel cache behavior is useful context. The proposed lifetime change still needs verification.

  3. DeusData commented on Oct 25, 2026

    @DeusData
    Owner

    Thank you for your patience. Sequential-result lifetime and the reparse tradeoff remain the review scope. Sorry for the delay; I’ll follow up soon.

  4. DeusData commented on Oct 29, 2026

    @DeusData
    Owner

    Fixed on main by #2418 (merge ba4122d): the sequential definitions pass no longer keeps every result with its parse tree and working arena alive until the end. On six projects indexed with one worker the graph is byte-identical and peak memory drops by 20 to 89 percent (for example django 3.50 to 0.55 GB). Thank you for the report and the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memory

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions