Repository navigation
refactor(stage1): scan widening as one operator over groups; one exact-guarantee strip (#1203 2a-5) - #1222
Closed
zzylol wants to merge 2 commits into
Closed
refactor(stage1): scan widening as one operator over groups; one exact-guarantee strip (#1203 2a-5)#1222zzylol wants to merge 2 commits into
zzylol wants to merge 2 commits into
Conversation
zzylol
force-pushed
the
refactor/1203-2a-4-rollup
branch
2 times, most recently
from
November 5, 2026 17:38
0373b2e to
280a6d4
Compare
zzylol
force-pushed
the
refactor/1203-2a-5-scan-labels
branch
from
November 5, 2026 17:54
5535471 to
470bc69
Compare
zzylol
force-pushed
the
refactor/1203-2a-4-rollup
branch
from
November 5, 2026 20:25
280a6d4 to
e707a43
Compare
zzylol
force-pushed
the
refactor/1203-2a-5-scan-labels
branch
from
November 5, 2026 20:31
470bc69 to
010cebc
Compare
zzylol
force-pushed
the
refactor/1203-2a-4-rollup
branch
from
November 5, 2026 21:13
e707a43 to
ac7fffd
Compare
zzylol
force-pushed
the
refactor/1203-2a-5-scan-labels
branch
from
November 5, 2026 21:14
010cebc to
362d7d9
Compare
Rule 2 (scan widening) adds its widened readers through `add_candidate_over_groups`, so the widened build, its readout, the narrowing projection and the widened source chains are groups, found or added with Stage 0's equality. This replaces the rule's own interning (`intern_inputs`, `same_source_node`) and its "already added" check. A widened root equal to a group's node is read through an identity projection (`Memo::group_with_equal_node`), and one output-contract check decides whether a widened reader is added. A widened tumbling-window reader is now groups, so rule 9 also takes a Stage 0 group's candidate whose one build is a tumbling-window chain beneath its groups (`build_read_by` -> `BuildPlace::BeneathGroups`): it rewrites the candidate whole, as it did the private chain, and stores the rewrite as one operator over groups. Stage 0's group nodes it puts back are computed once per rule run. Test: rollups lose nothing from widened readers whose chain is now beneath groups (rule 6 takes only private and input-group builds). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
… rule 9 without_exact_guarantees and without_exact_guarantees_below become one function (operator_over_groups keeps the candidate's own guarantee). Rule 9 compares build inputs by pointer only: equal TimeRange inputs are one group by Stage 0's equality since Pass 1 adds every intermediate result as a group, so same_range_input and same_local_fields are deleted.
zzylol
force-pushed
the
refactor/1203-2a-4-rollup
branch
from
November 5, 2026 21:24
ac7fffd to
947d5b3
Compare
zzylol
force-pushed
the
refactor/1203-2a-5-scan-labels
branch
from
November 5, 2026 21:24
362d7d9 to
21aca01
Compare
Contributor
Author
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.
Stacked on #1221; part of #1203, tracked in #1207 (PR 2a-5).
Merge unit. This PR merges into main only together with the rest of #1207's merge unit (steps 1a–6, #1207 "Order"): interim items below are deleted by a later PR in the unit.
Why
#1203 decided one operator per candidate, every intermediate result its own memo group. Scan widening (rule 2) still adds a consumer chain down to the widened source, and interns that source with its own equality (
same_source_node, which ignores guarantees).What
add_candidate_over_groups): the narrowing projection, the readout, the merge and the build beneath it are groups.Scan,TimeRange,TimeShift) are found or added with Stage 0's equality byadd_candidate_over_groupsitself (originWidenedScans). This replaces the rule's own interning (intern_inputs/same_source_node) and its "already added" check.SummaryTumblingWindowChainis rewritten whole at each shared layout or size, and the rewrite is stored as one operator over groups (BuildPlace::BeneathGroups).SummaryAggbuild group). Each tumbling-window width's merge is then its own group, so rule 9's per-group layout deduplication never applies: on the nine-query workload below that tried variant grew Stage 2 from 3340 to 4844 candidates and the devtools tests from 63 s to 1318 s.sum by (job)/sum by (region)ofsum_over_time(latency[5m]), the two queries' equalFinalizeExactAccumulatorconsumers of the shared build become one group. Cost 0.003267 → 0.003250 per second. Details in "Second review fixes".New abstractions not in #1207 or the doc: decisions (2026-11-05)
Per #1207's interface policy, these names are not defined by #1207, #1203 or section 3 of
memo-groups-properties-requirements.md. #1207's steps 1a–6 merge into main as one merge unit (#1207, Order), so an interim abstraction may stay in this PR only when a later PR of the unit deletes it; none reaches main. Rows marked Pending approval are not deleted by any PR in the unit and need the user's decision.SummaryStates::stage0_group_nodes(private field)SharedBuildSharedBuild, rule 9)without_exact_guarantees_below+reuse::without_exact_guaranteeswithout_exact_guarantees(interim until 2b)same_range_input,same_local_fields(pre-existing)TimeRangeinputs are one groupintern_inputs,same_source_nodeHow
The widened root is wrapped in an identity
Projectwhen a group's node equals it (Memo::group_with_equal_nodeon the root without exact guarantees), as before for a root that is itself a source chain.One output-contract check (
same_output_contract); thenadd_candidate_over_groupsfinds or adds every node beneath it, the widened source chains included.Rule 9's
setstakesbuild_of's place (refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215):PrivateandInputGroupas before;BeneathGroupsonly for a Stage 0 group's candidate whose one build down to Stage 0's groups is a chain.deriveputs back only Stage 0's group nodes after the rewrite (with_child_nodes, the node set collected once per run). It stores the rewrite withoperator_over_groups(added groups' originSharedBuild).Representation / rules / enumeration
find_or_add_group. Rule 9 matches a chain beneath a Stage 0 group's groups as it matched the private chain.Key code interfaces added / modified
crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs(crate-internal)crates/logical-asap-optimization/src/pass2/memo/rules/reuse.rs(crate-internal)crates/logical-asap-optimization/src/pass2/memo/rules/scan_labels.rs(crate-internal)Usage. On the KLL and scan-widening examples, rule 2 widens only the source groups (
Scan,TimeRange), whose candidates were already one operator:asap_planner --run-until stage1_pass2 --format textprints byte-identical output before and after. A widened consumer of a build fires instate_groups::tests::disjoint_scan_labels_share_a_union_tumbling_window_state_with_typed_readers(avg by (job) (quantile_over_time(0.95, latency[5m]))andavg by (region) (quantile_over_time(0.99, latency[5m])),max_error 0.01, with tumbling windows); its memo, printed from the test:Major algorithm changes
None.
Before this PR
Rule 2 added consumer chains and interned widened source chains with
same_source_node; rule 9 found a widened tumbling-window consumer's chain among its private nodes.After this PR
Rule 2 adds one operator over groups with groups found by Stage 0's equality; rule 9 finds the same chain beneath the consumer's groups and rewrites the consumer as before.
Deleted
scan_labels.rs:intern_inputs(add_candidate_over_groupsfinds or adds the source chains),same_source_node, the "already added" check and its deep==, the directpush_groupof widened source groups, theboundary_groupscall.shared_configuration_readers.rs:StateNeed::build_group(nowplace).with_source_chain_groups, scan widening's second output check,chain_beneath_groups,workload_group_nodes, rule 9's ownBuildPlace,state_groups::build_down_to_workload_groups.disjoint_scan_labels_share_a_union_tumbling_window_state_with_typed_readersandwidened_tumbling_window_inputs_preserve_series_identity_and_keysfind the union-label chain among all groups (it is now a group of rule 2, read by its merge group, not aSharedBuildgroup of step 10), and check every Stage 0 group's widened consumer of it.Plan cost, Stage 2 candidates and planning time
UPDATE_SNAPSHOTS=1left every snapshot file unchanged. Stage 2 physical candidates and--run-until stage3wall time per snapshot input, #1221 vs this PR, release builds on one host:Not a snapshot, but where rule 2 widens builds: the nine-query workload (
tools/dag-viewer/workloads/random-mixed-seed-862/workload-01.json, no raw data retained, the devtools tests' setting): selected cost 716.285846 before and after; Stage 2 candidates 3340 → 2812 (equal widened builds are one group);--run-until stage313.1 s → 11.4 s.Second review fixes (folded into
470bc69)sum by (job) (sum_over_time(latency[5m]))andsum by (region) (sum_over_time(latency[5m])), every 60 s,max_error 0.01.a2f8f18): both queries' widened consumers read the sharedSummaryAgggroup G16, each through its own privateProject ← FinalizeExactAccumulator, so the finalization was computed twice.FinalizeExactAccumulatornodes are one group (G17), and both consumers areProjectover G17.G2:c122 G6:c122 …→G2:c61 G6:c61 … G17:c0.add_candidate_over_groupschecked it again. Now scan widening checks it once (reuse::same_output_contract), on the node it adds.with_source_chain_groupsdeleted.add_candidate_over_groupsfinds or adds every node beneath the widened root, source chains included. Before, a widened root that was itself a source chain became a group's node by pointer. Now the aliasing check finds that group withMemo::group_with_equal_node, on the root without exact guarantees (reuse::without_exact_guarantees, shared withfind_or_add_producer).chain_beneath_groupsis deleted: rule 9 takesbuild_of'sBeneathGroupsplace (refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215), still only for a Stage 0 group's candidate whose build is a tumbling-window chain. Also deleted:BuildPlaceenum (it uses refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215's);state_groups::build_down_to_workload_groups(it was refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215'sbuild_down_to_stage0_groups);workload_group_nodes.SummaryStates::stage0_group_nodes), not once per rewrite.BeneathGroups), which rule 6 does not take. Before, the chain was a private build, which rule 6 did take.rollup_candidate_forfound no rollup for any of them.state_groups::tests::rollups_lose_nothing_from_widened_readers_whose_chain_is_beneath_groupschecks this onsum by (job)/sum by (job, region)ofsum_over_time(latency[5m])with tumbling windows.Notation (formulation → code)
MemoGroup, idMemoGroupIdadd_candidate_over_groupsProject) over the narrowing projection's group, down to the widened source-chain groupsMemo::group_with_equal_node(Stage 0's equality)Concepts not in the formulation
WidenedScans, rule 2): a consumer whose scans read the union of the labels its metric's consumers need, then project back. In the formulation these are memo groups for the widened scans plus candidates of the consumers' groups.BuildPlace::BeneathGroups): rule 9 rewrites such a candidate whole. Rule 9 is deleted in 2b (Logical memo candidate as (one operator over groups, logical properties θ) with a requirement per input; no private nodes #1203 decision 3).stage0_group_nodes), added groups, output contract, producer, accuracy budget parts: see refactor(stage1): Pass 1 adds a memo group for every intermediate result (#1203 PR 2a-1) #1215 / refactor(stage1): summary readouts and inputs as one operator over groups; Memo::add_candidate; one node equality in Pass 1 (#1203 2a-2) #1218.Second review verification (
470bc69)cargo test -p asap-types --lib: 146 passed.cargo test -p asap-logical-asap-optimization --lib: 199 passed (new:rollups_lose_nothing_from_widened_readers_whose_chain_is_beneath_groups).cargo test -p asap-integration-tests --test integration -- memo_enumeration reuse_rules operator_sharing sharing_issue_regressions finer_aggregate_reuse planner_layering_example having_shared_aggregate stage1_logical_asap_optimization joint_search_equivalence sketch_rollup rollup_controlled production_rollup_workloads: 154 passed, 23 ignored (pre-existing).cargo test -p asap-devtools --lib: 18 passed.--test devtools -- asap_planner:: asap_planner_acceptance:: memo_pricing::: 56 passed, 1 ignored.UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --include-ignored: 9 passed, no file changed.asap_planner --run-until stage1_pass2 --format text: byte-identical to the pre-review head5535471on the KLL and scan-widening examples and on 35 other workloads (the reviewer's 20 workloads including the two-query one above, six rollup / scan-widening /avgworkloads, five earlier finer-aggregate, rollup, top-k and scan-KLL examples,random-mixed-seed-862workloads 01–04). So the cost change above was already in this PR before the review fixes.cargo fmt --all;cargo clippy --workspace --all-targets -- -D warnings: clean.Restack on #1218 (
b8402c7)Rebased on #1218's interface alignment: the doc's
Memo::add_candidatereplacespush_candidate_if_new(same equality; returns the candidate'sCandidateForMemoGroupId), and #1218's CI fix ofsketch_rollup::quantiles_rolled_up_keep_the_sketch_bound. Plans unchanged.cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings: clean.cargo test -p asap-logical-asap-optimization --lib: 199 passed.cargo test -p asap-integration-tests --test integration -- scan widen label memo_enumeration: 28 passed, 2 ignored (pre-existing).Restack (2026-11-05)
On #1215's consumer naming (
build_of→build_of) and #1218's one node equality in Pass 1.without_exact_guarantees(was alsowithout_exact_guarantees_below); rule 9 compares build inputs by pointer, sosame_range_input/same_local_fieldsare deleted (equalTimeRangeinputs are one group).cargo test -p asap-logical-asap-optimization --lib: 199 passed, integration (12 filters as above): 154 passed, 23 ignored;UPDATE_SNAPSHOTS=1corpus snapshots: 9 passed, no file changed.cargo fmt --all -- --check;cargo clippy --workspace --all-targets -- -D warnings: clean;cargo test -p asap-logical-asap-optimization --lib: 198 passed.Viewer
Viewer tests not updated for the group shape (#1203 decision 6);
viewer_contractpasses.Verification
cargo test -p asap-logical-asap-optimization --lib: 198 passed.cargo test -p asap-physical-asap-optimization: 29 passed.cargo test -p asap-plan-selection --lib: 142 passed.cargo test -p asap-devtools --lib: 18 passed.cargo test -p asap-integration-tests --test integration -- memo_enumeration reuse_rules operator_sharing sharing_issue_regressions finer_aggregate_reuse planner_layering_example having_shared_aggregate stage1_logical_asap_optimization joint_search_equivalence sketch_rollup rollup_controlled production_rollup_workloads: 154 passed, 23 ignored (pre-existing).cargo test -p asap-devtools --test devtools -- asap_planner:: asap_planner_acceptance:: memo_pricing:: viewer_contract::: 58 passed, 1 ignored (63 s).UPDATE_SNAPSHOTS=1 cargo test --release -p asap-devtools --test corpus_snapshots -- --include-ignored: 9 passed, no file changed.cargo fmt --all;cargo clippy --workspace --all-targets -- -D warnings: clean.--run-until stage1_pass2 --format text: byte-identical to refactor(stage1): rollups as one operator over groups (#1203 2a-4) #1221's head.Left for 2a-6..k
Tumbling windows (1), rule 9's own outputs and step 10, then deleting
direct_input_builds,BuildPlace::Private,same_range_input,SharedBuildandSummaryResult, and the interimadded_groupshelpers (rule 9'sBeneathGroupspath usesMemo::is_stage0_groupuntil rule 9 is deleted in 2b).