perf(index): apply the warm-load cache by move — cut the startup RSS peak#207
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR reduces warm-load startup memory by eliminating a second in-memory copy of each FileData during the apply phase. It does this by making apply_workspace_result consume WorkspaceIndexResult and moving each FileData directly into the Indexer’s Arc<FileData>, while still emitting the same progress summary by capturing counts before the move.
Changes:
- Change
Indexer::apply_workspace_resultto takeWorkspaceIndexResultby value and drainresult.files, movingFileDataintoArc<FileData>via a newfile_contributions_owned. - Remove the
Arc<WorkspaceIndexResult>wrapper in the warm-apply path and capture progress summary counts up-front instead. - Update tests/docs in
apply_testsandmemory_probe_teststo reflect the new ownership/move behavior and expected apply-phase RSS profile.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/indexer/scan.rs | Captures progress counts before spawning apply, and passes WorkspaceIndexResult by value into apply_workspace_result to enable move-based apply. |
| src/indexer/memory_probe_tests.rs | Updates the probe narrative and call site to reflect apply_workspace_result consuming the result (no post-apply drop(result)). |
| src/indexer/apply.rs | Introduces file_contributions_owned and changes apply_workspace_result to consume and drain result.files, moving FileData into Arc without deep clones. |
| src/indexer/apply_tests.rs | Updates tests to pass WorkspaceIndexResult by value to the new apply_workspace_result signature. |
38ce988 to
43297e0
Compare
…S peak The warm-load path deep-cloned every file's FileData twice: once into the FileIndexResult vec (cache_entry_to_file_result) and again into the Indexer's Arc (file_contributions -> Arc::new(result.data.clone())). At apply time both copies coexisted, so the deserialized workspace footprint doubled and jemalloc retained the freed transient — users saw ~2x the necessary RSS after startup. Add file_contributions_owned, which moves FileData straight into its Arc, and make apply_workspace_result take WorkspaceIndexResult by value: it now drains result.files into the maps instead of cloning them, so the two full copies never coexist. finalize_workspace_scan drops its Arc<WorkspaceIndexResult> wrapping (the apply task and send_progress_end run sequentially, not concurrently) and captures the progress-end summary counts before moving result into apply. memory_retainer_profile apply peak: 487.1 MB -> 408.1 MB (-79 MB), with the eliminated ~130 MB of duplicated FileData exactly matching the drop in jemalloc-retained slack (207.9 MB -> 129.1 MB unaccounted). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB
43297e0 to
7c95d9d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
F0 of the memory plan: the warm-load apply path held the deserialized
WorkspaceIndexResultAND a second copy of everyFileDatasimultaneously (file_contributionscloned into the Indexer's Arcs whileresult.filesstill owned the originals), and jemalloc retained the freed transients — users saw ~2× the necessary RSS after startup.apply_workspace_resultnow consumesresultby value;file_contributions_ownedmoves eachFileDatainto itsArc(Arc::new(result.data), no clone).Arc<WorkspaceIndexResult>wrapper is gone — it existed only sosend_progress_endcould read counts after the spawn; the three counts are captured before the move. Review verified the sequentiality (apply is awaited before progress-end; no other holder), and that the old code never used the Arc for retry either.cache_entry_to_file_resultcopy) was implemented, measured at 0 MB peak effect (both builders free-as-they-go), and reverted — deferred to pair with the interning work.Measured (the probe in the base PR is the meter)
RSS apply peak: 487.1 → 408.1 MB (−79 MB); unaccounted slack 207.9 → 129.1 MB — the delta matches the eliminated single FileData duplication; the remaining slack is the genuinely-derived
FileContributionsmaps, which the planned file-id interning targets next.1440 tests green, clippy
-D warningsclean. Task-scoped review: Approved (no Critical/Important).Stacked on the probe PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EJsyQ1UgF8uJYR4HgpxEBB