refactor: sort/dedup lineage nodes once, not per-node#6084
Merged
Conversation
FrameCollector::fold_expr sorted and deduped the entire nodes vector on every node visit, making debug-lineage collection O(n² log n). Move the sort/dedup to run once after the full traversal in collect_frames; the result is identical since nothing reads nodes mid-traversal.
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
FrameCollector::fold_expr(insemantic/reporting.rs) is invoked once per expression node while building the debug-lineage node graph. On every one of those calls it re-ran:Since
fold_exprrunsntimes and each call sorts the growingnodesvector, collection was O(n² log n) for a query withnnodes — pure wasted work that scales badly on large queries. Nothing readsself.nodesmid-traversal, so the intermediate sorts served no purpose; only the final ordered/deduped vector is used (bycollect_frames, for the parent-linking pass).Solution
Move the sort + dedup out of the per-node
fold_exprand intocollect_frames, running them once after the full traversal completes (mirroring howcollect_framesalready doesframes.reverse()and parent-linking after folding). This drops the work to a single O(n log n) sort. The finalnodesvector is byte-for-byte identical, because a single sort+dedup after all pushes produces the same canonical result the repeated in-loop sorts converged to.Testing
This is a behavior-preserving change, so there is no "fails-before / passes-after" regression test to add — output is unchanged by construction. Correctness is guarded by the existing
debug_lineageintegration snapshots, which serialize the full node graph thatcollect_framesproduces:queries::debug_lineage::*snapshot tests pass unchanged.reporting/lineagelib tests pass.Found during the nightly code-quality survey.