Skip to content

refactor(stage1): rollups as one operator over groups (#1203 2a-4) - #1221

Closed
zzylol wants to merge 2 commits into
refactor/1203-2a-3-topk-finer-aggregatefrom
refactor/1203-2a-4-rollup
Closed

zzylol wants to merge 2 commits into
refactor/1203-2a-3-topk-finer-aggregatefrom
refactor/1203-2a-4-rollup

Conversation

@zzylol

@zzylol zzylol commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #1220; part of #1203, tracked in #1207 (PR 2a-4).

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. After #1220, rollups (rules 6 and 7) are the last users of the old chain-adding helpers: they still add consumer chains such as SummaryEstimate ← SummaryMerge(regroup) and rebind rewritten nodes to group nodes with their own equality.

What

  • Rules 6 (add_rollup_candidates) and 7 (add_window_rollup_candidates) add their consumer copies as one operator over groups (add_candidate_over_groups): the regrouping SummaryMerge, and for an exact rollup the finalization and its value producer, are groups. Rule 6's exact value producer is found or added with Stage 0's equality (find_or_add_producer).
  • The rewritten nodes find the groups they repeat by Stage 0's equality, so the rules' own rebinding to group nodes is deleted (restore_inputs, reuse::same_node, combined_inputs), and with their last users gone, append_reader and append_producer.
  • Plans unchanged: no snapshot file changes; Stage 2 candidate counts identical on every snapshot input.

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.

Abstraction What it is for Decision
append_reader, append_producer, combined_inputs, restore_inputs, reuse::same_node old chain helpers Deleted in #1221
path_to_state (private test helper, integration-tests/src/lib.rs) the candidates on a path of groups down to a state Pending approval. Recommendation: keep (test-only, shared by three rollup tests)

How

  1. Rules 6 and 7 call reuse::add_candidate_over_groups (refactor(stage1): summary readouts and inputs as one operator over groups; Memo::add_candidate; one node equality in Pass 1 (#1203 2a-2) #1218) with the rewritten coarse / fine roots, where they called restore_inputs and then append_reader.
  2. Rule 6 calls reuse::find_or_add_producer for the finalized value it shares, where it called append_producer.
  3. integration-tests' select_rollup (the fixed plans the rollup tests price) now follows each query's path of groups from its own summary candidate down to the shared build, since the regrouping merge sits one group lower than before; it no longer needs groups_read_through_added_groups, whose test_support re-export is deleted.

Representation / rules / enumeration

  • (a) Representation. Unchanged types. Candidates of rules 3–8 are one operator over groups; rules 1, 2, 9 and step 10 still add chains.
  • (b) Rules. Rules 6 and 7 extend the memo through find_or_add_group. Their matching is unchanged: rule 6 still takes a Pass 1 or widened-scan candidate's private build or its build input group (build_of, places Private / InputGroup); rule 7 still reads tumbling-window candidates' private chains (Private).
  • (c) Enumeration. Unchanged.

Key code interfaces added / modified

crates/logical-asap-optimization/src/pass2/memo/rules/reuse.rs (crate-internal)

/// Rebinds a rewritten node's subtrees to equal input-group nodes. // removed
pub(in crate::pass2::memo) fn restore_inputs(node: &Rc<OperatorNode>, memo: &Memo, inputs: &[MemoGroupId]) -> Rc<OperatorNode>;
/// The rules' own node equality. // removed (Stage 0's equality decides)
pub(in crate::pass2::memo) fn same_node(left: &OperatorNode, right: &OperatorNode, guarantees: bool) -> bool;
/// Adds a dedicated producer group. // removed (find_or_add_producer)
pub(in crate::pass2::memo) fn append_producer(memo: &mut Memo, node: Rc<OperatorNode>, queries: &[usize],
    origin: OriginOfCandidateForMemoGroup, accuracy_budget_parts: usize) -> Result<MemoGroupId, Pass2RuleError>;
/// Adds a reader chain to a group. // removed (add_candidate_over_groups)
pub(in crate::pass2::memo) fn append_reader(memo: &mut Memo, owner: usize, original: &CandidateForMemoGroup,
    node: Rc<OperatorNode>, origin: OriginOfCandidateForMemoGroup) -> Result<bool, Pass2RuleError>;
/// Both candidates' input groups. // removed
pub(in crate::pass2::memo) fn combined_inputs(left: &CandidateForMemoGroup, right: &CandidateForMemoGroup) -> Vec<MemoGroupId>;

crates/logical-asap-optimization/src/added_groups.rs

pub(crate) struct GroupsReadThroughAddedGroups { /* fields unchanged */ } // was pub, re-exported
pub(crate) fn groups_read_through_added_groups(memo: &Memo, inputs: &[MemoGroupId])
    -> GroupsReadThroughAddedGroups; // was pub, re-exported

Usage. No rollup fires on the KLL example; asap_planner --workload kll.json --run-until stage1_pass2 --format text (and the scan-widening workload) print byte-identical output before and after. A workload where rule 6 fires: quantile by (host, job) (0.5, data) and quantile by (job) (0.5, data), rank max_error 0.01, failure probability 0.001, every 10 s, data 10,000 gauge series every 15 s. asap_planner --run-until stage1_pass2 --format text, Pass 2 output:

# before (#1220)
G6:   SummaryAgg Kll(failure_probability=1e-7 k=567)  <- G1      # by (host, job)
G8:   SummaryAgg Kll(failure_probability=1e-7 k=567)  <- G4      # by (job)
G9:   SummaryEstimate Quantile(q=0.5)                 <- G8
    [0]  Pass1   SummaryEstimate Quantile(q=0.5)                  inputs=[G8]
    [1]  Rollup  SummaryEstimate Quantile(q=0.5) ← SummaryMerge   inputs=[G6]
# after
G9:   SummaryEstimate Quantile(q=0.5)                 <- G8
    [0]  Pass1   SummaryEstimate Quantile(q=0.5)  inputs=[G8]
    [1]  Rollup  SummaryEstimate Quantile(q=0.5)  inputs=[G10]
G10:  SummaryMerge                                    <- G6      # by (job) regrouped from G6's state
    [0]  Rollup  SummaryMerge  inputs=[G6]

Major algorithm changes

None.

Before this PR

Rollups rebuilt their rewritten roots over group nodes with their own equality (restore_inputs / reuse::same_node, guarantees compared only for states) and added consumer chains (append_reader) and producer groups (append_producer).

After this PR

Rollups add one operator over groups; Stage 0's equality is the only one the Pass 2 reuse rules use to find groups.

Deleted

  • reuse.rs: restore_inputs, same_node, append_producer, append_reader, combined_inputs.
  • test_support's re-export of groups_read_through_added_groups (no user left); added_groups items are now pub(crate).
  • select_rollup's one-level consumer lookup through groups_read_through_added_groups (now path_to_state).
  • Test changes (shape only, same intent): state_groups::tests::sketch_rollup_exposes_shared_finer_state and grouped_window_rollup_exposes_one_finer_chain now look for the rollup's regrouping-merge group over the finer build (they looked for a SharedBuild consumer of a private rollup chain); rollup::tests::a_rollup_reads_the_finer_query_result_itself checks that the coarse rollup reaches the finer query's group through its own groups; state_groups::tests::same_capacity_readers_retain_distinct_failure_probability_contracts tests add_candidate_over_groups (and that an equal candidate is not added twice).

Plan cost, Stage 2 candidates and planning time

UPDATE_SNAPSHOTS=1 left every snapshot file unchanged. Stage 2 physical candidates and --run-until stage3 wall time per snapshot input, #1220 vs this PR, release builds on one host:

snapshot Stage 2 candidates, before after seconds, before after
o11y_bench/q02 248 248 0.12 0.12
o11y_bench/q05 498 498 0.24 0.24
o11y_bench/q06 251 251 0.11 0.11
o11y_bench/q11 7 7 0.02 0.02
o11y_bench/q12 2 2 0.01 0.01
o11y_bench/q18 737 737 0.29 0.28
o11y_bench/q19 495 495 0.26 0.26
o11y_bench/q20 4 4 0.01 0.01
o11y_bench/q21 368 368 0.11 0.11
o11y_bench/q22 247 247 0.10 0.10
o11y_bench/q23 247 247 0.10 0.10
o11y_bench/q25 495 495 0.26 0.26
o11y_bench/q26 247 247 0.11 0.10
o11y_bench/q27 4 4 0.01 0.01
sketch/shared-quantiles-1h-mvp 1801 1801 0.88 0.88
sketch/nested-windows-15m-1h-mvp 2281 2281 1.23 1.24
sketch/ratio-of-quantiles-1h-mvp 1802 1802 2.49 2.52
sketch/quantile-single-mvp 201 201 0.08 0.08
sketch/quantile-grouped-mvp 108 108 0.06 0.06
sketch/topk-rate-guarantees-ignored-mvp 87 87 0.05 0.05
sketch/fuzz-issue903-raw-retained 135 135 0.08 0.07
sketch/random-mixed-seed-862-w02-q2-q7-mvp 136 136 0.09 0.09
sketch/random-mixed-seed-862-w01-q3-q8-mvp 226 226 0.11 0.11
sketch/random-mixed-seed-862-long-w01-q3-mvp 72 72 0.09 0.09
total 6.91 6.93

Second review fixes (folded into bb7d4a8)

Notation (formulation → code)

Formulation (#1203, #1201, #1207) Code name in this PR
memo group $G$ MemoGroup, id MemoGroupId (rollup owners coarse_group, fine_group)
candidate $v$ added to $G$ (over groups) add_candidate_over_groups
expression $e_v = \operatorname{op}v(G{v,1..n})$ of a rollup consumer the consumer copy's root over the regrouping SummaryMerge group (and, for an exact rollup, the finalization and value groups)

Concepts not in the formulation

Second review verification (bb7d4a8)

  • cargo test -p asap-types --lib: 146 passed. cargo test -p asap-logical-asap-optimization --lib: 198 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 --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.
  • KLL and scan-widening --run-until stage1_pass2 --format text: byte-identical to a2f8f18.
  • cargo fmt --all; cargo clippy --workspace --all-targets -- -D warnings: clean.
  • asap_planner --run-until stage1_pass2 --format text: byte-identical to the pre-review head a2f8f18 on 35 workloads besides the two examples: the reviewer's 20 workloads, six rollup / scan-widening / avg workloads, five earlier finer-aggregate, rollup, top-k and scan-KLL examples, and random-mixed-seed-862 workloads 01–04.

Restack on #1218 (b8402c7)

Rebased on #1218's interface alignment: the doc's Memo::add_candidate replaces push_candidate_if_new (same equality; returns the candidate's CandidateForMemoGroupId), and #1218's CI fix of sketch_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: 198 passed.
  • cargo test -p asap-integration-tests --test integration -- rollup sketch_rollup production_rollup_workloads reuse_rules: 25 passed.

Restack (2026-11-05)

On #1215's consumer naming (build_of → build_of) and #1218's one node equality in Pass 1.

  • cargo fmt --all -- --check; cargo clippy --workspace --all-targets -- -D warnings: clean; cargo test -p asap-logical-asap-optimization --lib: 197 passed.

Viewer

Viewer tests not updated for the group shape (#1203 decision 6); viewer_contract passes.

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). sketch_rollup_planning and rollup_controlled::memo_offers_one_kmv_build_and_a_rollup price the same build-plus-rollup plans as before (through path_to_state); rollup_controlled's production search still selects one KMV build and a rollup.
  • cargo test -p asap-devtools --test devtools -- asap_planner:: asap_planner_acceptance:: memo_pricing:: viewer_contract::: 58 passed, 1 ignored.
  • 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.
  • KLL and scan-widening --run-until stage1_pass2 --format text: byte-identical to refactor(stage1): top-k reuse and finer-aggregate reads as one operator over groups (#1203 2a-3) #1220's head.

Left for 2a-5..k

Scan widening (2), tumbling windows (1), state configurations (9) and step 10, then deleting direct_input_builds, BuildPlace::Private, same_range_input, SharedBuild and SummaryResult, and the interim added_groups helpers.

@zzylol zzylol added CSE optimizer Workload optimization and plan selection refactor labels Nov 5, 2026
@zzylol
zzylol force-pushed the refactor/1203-2a-3-topk-finer-aggregate branch from c4f1267 to 9fbfc54 Compare November 5, 2026 16:01
@zzylol
zzylol force-pushed the refactor/1203-2a-4-rollup branch from a2f8f18 to 0373b2e Compare November 5, 2026 16:21
@zzylol
zzylol force-pushed the refactor/1203-2a-3-topk-finer-aggregate branch from 9fbfc54 to 7e3d360 Compare November 5, 2026 17:23
@zzylol
zzylol force-pushed the refactor/1203-2a-4-rollup branch from 0373b2e to 280a6d4 Compare November 5, 2026 17:38
@zzylol
zzylol force-pushed the refactor/1203-2a-3-topk-finer-aggregate branch from 7e3d360 to e8f39e8 Compare November 5, 2026 20:19
@zzylol
zzylol force-pushed the refactor/1203-2a-4-rollup branch from 280a6d4 to e707a43 Compare November 5, 2026 20:25
@zzylol
zzylol force-pushed the refactor/1203-2a-3-topk-finer-aggregate branch from e8f39e8 to c418afa Compare November 5, 2026 21:13
@zzylol
zzylol force-pushed the refactor/1203-2a-4-rollup branch from e707a43 to ac7fffd Compare November 5, 2026 21:13
zzylol and others added 2 commits November 5, 2026 21:24
Rules 6 (rollup) and 7 (window rollup) add their reader copies through
`add_candidate_over_groups`, and rule 6's exact value producer through
`find_or_add_producer`, so a rollup's regrouping merge and finalization
are groups. Their rewritten nodes find the groups they repeat by Stage
0's equality, so the rule's own rebinding (`restore_inputs`,
`reuse::same_node`, `combined_inputs`) is deleted, and with the last users
gone, `append_reader` and `append_producer`.

Second review fixes, folded in on the rebase: the rewritten roots are
taken out of the rule's result by value (no Rc::clone rebinding), owners
are MemoGroupId, and find_or_add_producer has no budget-parts argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
…wn to the shared state

select_rollup chooses, for each query, its own summary candidate and the
candidates on a path of groups from it to the shared build (a rollup's
regrouping merge is now a group of its own), instead of one reader group
found through groups_read_through_added_groups. Its test_support
re-export, now unused, is deleted; the interim helpers are crate-private.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ
@zzylol

zzylol commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Closed: replaced by #1207's new order (interfaces first, then one PR per stage), starting with PR 0 #1226. The code on this branch is reused in PRs 1–8; the branch is kept.

@zzylol zzylol closed this Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CSE optimizer Workload optimization and plan selection refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant