Repository navigation
feat: derive ingestion refresh groups and refresh each group in one run (#1151) - #1153
Merged
Merged
Conversation
zzylol
force-pushed
the
feat/1151-refresh-groups
branch
from
October 31, 2026 18:58
5a156af to
7e87761
Compare
zzylol
changed the base branch from
feat/1151-refresh-docs
to
feat/1095-stage3
October 31, 2026 19:36
…ws; chains count in a reader's window (#1151)
zzylol
force-pushed
the
feat/1151-refresh-groups
branch
from
October 31, 2026 19:37
7e87761 to
01d4b49
Compare
zzylol
added a commit
that referenced
this pull request
Nov 2, 2026
…ge (#1151, lands #1152–#1154 on main) (#1182) * docs: refresh the ingestion-time views of one refresh window in one run (#1151) (#1152) The deployment contract refreshes the ingestion-time views of one refresh window in one run per window end; the run's roots are the group's views whose state for that window is not yet stored. Part of #1151. * feat: derive ingestion refresh groups and refresh each group in one run (#1151) (#1153) RefreshWindow, PhysicalASAPDAG::refresh_window and ingestion_refresh_groups derive which ingestion-time views share one run; the install compile check and the stand-in runtimes refresh per group, and a counting-store test shows one raw read per window per group. No cost change. Part of #1151. * feat: charge a shared ingestion node once per refresh window (#1151) (#1154) asap_cost::execution_demand::computations counts a NotMaterialized ingestion-time node once per refresh window of its MatAtIngestion consumers instead of once per consumer, and the old Stage 3 engine (general_schedule, DirectCostProfile::selected_cost, direct_cost::encode) charges it the same way. Snapshots unchanged. Closes #1151 except the backend follow-up. * fix: use the tumbling-window names (#1163) in the refresh-window code rebased onto main The refresh-window commits (#1152-#1154) were written before #1163 renamed PaneChain to SummaryTumblingWindowChain and pane_width_ms / pane_count / newest_panes to tumbling_window_width_ms / tumbling_window_count / newest_tumbling_windows; rename their uses so they build on main.
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.
Why
Part of #1151, stacked on #1152 (the deployment contract). With a KLL chain and a DDSketch chain of 10 s panes kept at ingestion over one
Scan, the Planner's install check and its stand-in runtimes refresh each pane view in its own ingestion run, so each pane window is read from raw data twice. The contract in #1152 says to refresh the views of one refresh window in one run. This PR adds the derived API that names the groups, compiles each group as one run in the install check, and makes the stand-in runtimes refresh by group. It does not change the cost rule; that comes in the next PR.What
asap-types: next tomaterialized_views(). All are derived from the DAG. Nothing new goes in the plan file, so there is no wire-version bump.RefreshWindow(with the one constructorRefreshWindow::of_window) andIngestionRefreshGroup.PhysicalASAPDAG::refresh_window/refresh_windows.PhysicalASAPDAG::ingestion_refresh_groupsandingestion_refresh_groups_of(views), for a caller that already derived the views.view_windowsnow counts an unexpandedPaneChainbelow a node as all its panes, so a node above a chain on the DAG Stage 3 costs has a refresh window. The installed DAG has no chains, so nothing changes for the executor.asap-planner:InstallablePlan::ingestion_refresh_groups()delegates to the DAG.executor_compiles, behindplan_installableandcheck_compiles) now compiles one refresh per refresh group, plus one per view refreshed on first read. Before, it compiled one refresh per view.ingestion_refresh_groups_of) instead of deriving them again.reasonnames every view compiled with it.crates/planner/tests/runtime_install.rs: one ingestion run per (group, window end). Its roots are the group's views whose state for that window is not stored yet (the newest pane of each chain once older panes are stored). A view of the group that a root reads is computed in the run.crates/integration-tests/tests/materialization_e2e.rs: one compile per group.DataStorechecks oneread_raw_datacall per pane window, the same states as per-view runs, and answers equal to the query-time reference.ingestion_refresh_groups,IngestionRefreshGroupandRefreshWindow. The running example calls it. §6 lists the new runtime test.How
refresh_windows(nodes)gives each node's refresh window:PaneChain(the unexpanded DAG Stage 3 costs), it is(pane_width_ms, s mod pane_width_ms), wheresis the sum of theTimeShiftoffsets below the chain. That is the newest pane's window.(W, o mod W)of itsview_window(T - o - W, T - o].Nonewhen the window is unbounded or empty.Pane
iof a chain readsTimeRange(W) ← TimeShift(i·W + s), so every expanded pane has its chain's refresh window.ingestion_refresh_groups()works in three steps:materialized_views()(dependency order).Nonewindow is a group of its own, and each group keeps dependency order.Key code interfaces added / modified
crates/types/src/ir/materialized_view.rscrates/types/src/ir/physical_export.rscrates/planner/src/installable.rs,crates/planner/src/lib.rsUsage (the new runtime test
panes_of_one_refresh_window_read_each_raw_window_once, run at this commit):Major algorithm changes
Refresh grouping (installation and stand-in runtimes)
read_raw_datacalls at the first evaluation, one per pane view. The 6 KLL panes and the newest 6 DDSketch panes cover the same 6 windows.compile(dag, reads, [view])and run it.ingestion_refresh_groups()groups the views by refresh window.(s, e]builds, for every root, the window ending ate. Views with one refresh window and the same span read exactly(s, e]. The executor runs each shared node once perexecute. The test checks every grouped state against the state its view builds alone, and the answers against the query-time reference.refresh_windowsis O(nodes + edges).ingestion_refresh_groupsadds O(views + reads) tomaterialized_views.executor_compilesnow compiles fewer refreshes, each over the nodes below all of its roots. The existing 300-pane check (view_refreshes_compile_only_the_nodes_below_them) still holds the compiled nodes at ≤ 6× the plan.Before this PR
The install check and the Planner's stand-in runtimes compiled and ran one ingestion refresh per view, so a
Scanunder two equal-width chains was read once per chain per window. Nothing in the API named which views can share a run.After this PR
A runtime reads the groups from
InstallablePlan::ingestion_refresh_groups()(or the DAG method) and runs each group once per window. The install check compiles exactly those runs. The stand-in runtimes show one raw read per pane window for the example. The cost rule does not change yet.Verification
left: 36, right: 30raw-data reads.cargo test -p asap-types --test types: 103 passed, 6 of them new inmaterialized_view.cargo test -p asap-planner --test planner runtime_install: 41 passed, 1 of them new. One unrelated test hit its MILP deadline under machine load (a_quantile_shared_with_a_ratio_is_sized_for_the_ratio) and passed on rerun.cargo test -p asap-executor: all passed.view_windows, which the executor calls, changed.cargo test -p asap-planner --lib: 11 passed, includingview_refreshes_compile_only_the_nodes_below_them.cargo test -p asap-integration-tests --test integration materialization_e2e: 3 passed, 1 ignored (as before).cargo fmt --all --checkandcargo clippy -p asap-types -p asap-planner -p asap-integration-tests -p asap-executor --all-targets -- -D warnings: clean.Note: with 1 s samples (the issue's first example), the Planner picks 1 s panes for the DDSketch chain and 10 s panes for the KLL chain today, so they are two groups. The test samples every 10 s so that both chains get 10 s panes.
🤖 Generated with Claude Code