fix(lsp): seal shared Tier-2 cross-registry against O(n^2) resolve hang#677
Open
DeusData wants to merge 1 commit into
Open
fix(lsp): seal shared Tier-2 cross-registry against O(n^2) resolve hang#677DeusData wants to merge 1 commit into
DeusData wants to merge 1 commit into
Conversation
The per-file C cross-LSP resolver mutated the finalized, project-wide cross
registry that is shared read-only across the parallel resolve workers. Each
post-finalize add landed in a tail the hash index does not cover, so every
lookup linear-scanned an ever-growing tail -> O(files*defs) on large C
codebases. The Linux-kernel full index hung at "[4/9] Resolving" on 11 cores
for >6 min and never finished, plus a heap data race across workers.
Seal every shared cross-registry: CBMTypeRegistry gains a read_only flag, set
by all five {c,py,cs,ts,go}_build_cross_registry builders right after
finalize, and cbm_registry_add_func/_type no-op on a sealed registry. One
chokepoint guards every language, robust to any resolver mutation site. The
plain-C function-registration site is also skipped directly when the registry
is shared.
Add six cross-language invariant tests (c, c++, py, c#, ts, go): resolving
against a finalized shared registry must leave func_count/type_count
unchanged -- RED before the fix (C +1, C++ +2 post-finalize adds), GREEN
after.
Verified: full suite 5720 passed / 0 failed; Linux-kernel full index now
completes all 9 phases in 643s (4.88M nodes, 11.9M edges) instead of hanging
at phase 4.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
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.
Problem
In
fullmode the pipeline builds one project-wide C cross-registry (cbm_c_build_cross_registry), finalizes it (O(1) hash lookups), and shares it read-only across the parallel resolve workers (registry_shared = true). But the per-file C cross-LSP resolver still mutated that finalized, shared registry (c_lsp.cadd_funcsites). Each post-finalize add lands in a tail the hash index does not cover, so every subsequent lookup linear-scans an ever-growing tail -> O(files * defs). The Linux-kernel full index hung at[4/9] Resolvingon 11 cores for >6 min and never finished, plus a heap data race across workers.This is the documented "read-only shared registries" rule (036a80e) that was written down but only partially enforced — one site was guarded, the others were not.
Fix
Seal every shared cross-registry at the single chokepoint:
CBMTypeRegistrygains aread_onlyflag.cbm_{c,py,cs,ts,go}_build_cross_registrybuilders set ittrueright afterfinalize.cbm_registry_add_func/cbm_registry_add_typeno-op on a sealed registry.One guard covers every language and is robust to any resolver mutation site. The plain-C function-registration path is also skipped directly when the registry is shared. Languages that build a per-file registry (Java, Kotlin, Rust, PHP) are unaffected (per-file registries are never shared) and the seal future-proofs them if they ever become Tier-2.
Tests
Six cross-language invariant tests (
tests/test_c_lsp.c): resolving against a finalized shared registry must leavefunc_count/type_countunchanged — RED before the fix (C +1, C++ +2 post-finalize adds), GREEN after.Local verification (Apple M3)
start_kernelcallees matchinit/main.cline-for-line;lsp_direct0.95-confidence cross-file resolutions intact — no resolution-quality loss.CI is requested to verify across all platforms (Linux x64/arm64, macOS arm64/Intel, Windows).