Skip to content

feat!: install the Planner's InstallablePlan; depend on asap-planner and asap-executor only - #828

Draft
zzylol wants to merge 2 commits into
feat/range-queriesfrom
feat/repin-plan-installable
Draft

zzylol wants to merge 2 commits into
feat/range-queriesfrom
feat/repin-plan-installable

Conversation

@zzylol

@zzylol zzylol commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Stack 1/4 of the runtime work on top of #825. Base: #825.

Why

ASAPPlanner main now has the deployment handoff: one plan_installable call returns an InstallablePlan, which lists the outputs to store (with built_at, pane window and retention_ms) and the raw windows read at query time. Samples go through asap_executor::RawSampleSelector. Until now the backend rebuilt all of this itself. It expanded pane chains, searched the timing frontier, encoded PromQL rows, rebuilt the query-time reference and kept panes by its own "largest offset + 2 widths" rule. The design doc's boundary says the Planner decides what to compute and the backend decides how.

What

  • Re-pin to ASAPPlanner main f0dc1825. Among Planner crates the workspace depends only on asap-planner and asap-executor. IR types are reached through asap_executor::planner. The sync script and its test now update two dependencies.
  • Control plane: plan_workload calls asap_planner::plan_installable and returns its InstallablePlan, which save_plan writes as plan.json. Non-PromQL workloads are refused by the Planner's own frontend check. New --plan-selection-settings <json> (cost model, prices, speed, measured costs).
  • Data plane:
    • The SDS reads stored_outputs. IngestionRun outputs are built at ingestion and QueryRun outputs are kept across evaluations; panes and offsets come from each output's pane.
    • Identity is still the SDS's own (sub-DAG hash, offset-only TimeShifts transparent).
    • Each definition is kept for the largest retention_ms among its outputs. A pane is evicted once it starts before newest evaluation − retention. For stored panes, the newest evaluation is taken as the newest closed pane.
    • Pane and raw-window rows come from RawSampleSelector (Scan matchers, instant-selector latest sample).
    • Query-time raw windows come from query_time_raw_windows.
    • Answer labels come from series_labels_of_output_row.
    • New --execution-memory-limit-mib (the benefit harness passes it).
  • Deleted: the backend's pane-chain expansion, the Stage 1–3 plumbing and query-time reference rebuild in the control plane (plan_selected_at_query_time), frontier_from_timing, promql_rows, and the SDS's own shape walk. Shape errors are now the Planner's (InstallablePlanError).

How

Sds::from_plan folds stored_outputs into definitions by identity, taking the max retention. PaneBuild compiles a definition's builder from its TimeRange and feeds it RawSampleSelector::rows(end, samples). QueryEngine compiles each InstalledQuery.root_node_id, cut at stored outputs, kept outputs and query_time_raw_windows. Tests compare against InstallablePlan::query_time_reference().

Before this PR

plan.json was the backend's own InstalledPlan {queries, dag}. The data plane derived stored outputs with frontier_from_timing, kept panes for max offset + 2 × width, and built rows with promql_rows::series_row. A range query over panes older than the newest instant evaluation was answered from that slack.

After this PR

plan.json is the Planner's InstallablePlan, and the backend reads what to store and for how long from it. Example 4b without raw data: one definition of six 10-minute KLL panes, kept 60 min. A range evaluation the workload declares (range_evaluation) extends the retention. A range query reaching further back than the workload declares now reads an evicted pane and is forwarded with the reason.

Verification

Benefit harness (release, Prometheus 3.5.0)

Setup: bench on exp/benefit-harness as a tool (unchanged), examples workload, 90 min of data, one sample per series every 15 s. Prices: AWS Fargate us-east-1 (cost model 1); measured operation costs as before. Prometheus is pinned to 4 cores and the data plane to another 4. s10 = 2,000 series, s50 = 10,000. CPU is core-seconds over the whole run. Latency is per query, p50 / p99 ms.

s10

Run Prometheus core-s Data plane core-s Data plane peak RSS GiB rate p50/p99 ms topk p50/p99 ms p99[5m] p50/p99 ms p99[60m] p50/p99 ms forwarded
Prometheus alone 18.9 - - (Prometheus 0.09) 9.8 / 20.2 10.1 / 21.1 20.7 / 35.2 98.0 / 146.4 -
before 20.2 44.6 0.33 38.8 / 60.6 38.6 / 65.4 122.7 / 194.3 910.9 / 1163.4 0
pr1 20.2 43.9 0.37 37.0 / 57.8 37.6 / 55.7 123.9 / 156.9 1010.5 / 1175.0 0

s10-noraw

Run Prometheus core-s Data plane core-s Data plane peak RSS GiB rate p50/p99 ms topk p50/p99 ms p99[5m] p50/p99 ms p99[60m] p50/p99 ms forwarded
Prometheus alone 18.3 - - (Prometheus 0.09) 9.2 / 18.9 9.4 / 19.5 20.8 / 39.1 96.2 / 140.5 -
before 6.0 38.2 0.35 25.4 / 242.3 20.0 / 41.5 53.7 / 93.1 99.2 / 116.0 5
pr1 9.8 30.1 0.29 25.9 / 205.8 20.7 / 25.2 51.9 / 90.0 87.2 / 117.8 325

s50

Run Prometheus core-s Data plane core-s Data plane peak RSS GiB rate p50/p99 ms topk p50/p99 ms p99[5m] p50/p99 ms p99[60m] p50/p99 ms forwarded
Prometheus alone 85.0 - - (Prometheus 0.14) 42.8 / 74.2 42.5 / 79.3 96.9 / 136.2 419.4 / 652.4 -
before 95.0 248.0 1.58 225.6 / 325.3 219.1 / 330.4 690.4 / 925.9 4687.7 / 5850.2 0
pr1 96.9 216.9 1.89 200.5 / 246.0 197.4 / 240.4 646.5 / 817.6 4887.2 / 5982.6 0

s50-noraw

Run Prometheus core-s Data plane core-s Data plane peak RSS GiB rate p50/p99 ms topk p50/p99 ms p99[5m] p50/p99 ms p99[60m] p50/p99 ms forwarded
Prometheus alone 90.4 - - (Prometheus 0.14) 45.6 / 75.7 45.4 / 73.6 99.4 / 141.2 418.3 / 569.7 -
before 27.9 200.6 1.67 129.0 / 1358.4 109.7 / 122.7 315.9 / 359.5 409.3 / 516.5 5
pr1 47.1 190.8 1.47 157.9 / 1285.2 123.1 / 153.8 356.7 / 401.9 441.3 / 592.9 325

Forwarded evaluations without raw data (5 → 325). The harness evaluates example1 every 10 s right after writing samples up to 5 s later. By then the newest closed pane is past the evaluation time. Measured from that pane, the plan's 60-second retention for the 10-s panes evicts the oldest pane the evaluation reads. One evaluation in three of each example1 query is forwarded ("pane … is not stored"). The old rule's extra pane width hid this. Where "newest evaluation time" sits for ingestion-built panes is an open design question, reported separately; it is not settled in this PR.

Planner gaps found

  • RawSampleSelector::rows takes owned Samples with an owned label BTreeMap, so every buffered or fetched sample is copied into a new map before selection. Smallest fix: accept &[impl Borrow<Sample>] or Arc labels.
  • asap_planner does not re-export QueryLanguage, so a runtime cannot name the workload language without depending on asap-types.
  • plan_installable is async for the SQL frontend only; a PromQL runtime blocks on it.

…and asap-executor only

Re-pin ASAPPlanner to main f0dc1825 and use its handoff API.

- The control plane calls `asap_planner::plan_installable` once and writes
  the returned `InstallablePlan` as plan.json. The backend's own pane-chain
  expansion, Stage 2/3 plumbing and query-time reference rebuild are gone;
  tests use `InstallablePlan::query_time_reference`.
- The data plane reads `stored_outputs` (built_at, pane window,
  retention_ms) and `query_time_raw_windows`, and selects every pane's and
  raw window's rows with `asap_executor::RawSampleSelector`. It no longer
  uses `frontier_from_timing` or `promql_rows`.
- The SDS keeps its own identity (sub-DAG hash, offset-only TimeShifts
  transparent) and keeps each definition for the largest `retention_ms`
  among its outputs, measured from the newest evaluation that can read it,
  instead of "largest offset plus two pane widths".
- Among Planner crates the workspace depends on `asap-planner` and
  `asap-executor` only; IR types come through `asap_executor::planner`.
- `--plan-selection-settings` on the control plane and
  `--execution-memory-limit-mib` on the data plane, which the benefit
  harness passes.
@zzylol zzylol added enhancement New feature or request area: control plane Planning, configuration, routing, and control-plane orchestration area: data plane Runtime ingestion, storage, and query-serving data paths integration: ASAPPlanner ASAPPlanner API, IR, candidate, and selected-plan integration test: end-to-end Process-boundary, differential, conformance, and full-stack tests labels Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: control plane Planning, configuration, routing, and control-plane orchestration area: data plane Runtime ingestion, storage, and query-serving data paths enhancement New feature or request integration: ASAPPlanner ASAPPlanner API, IR, candidate, and selected-plan integration test: end-to-end Process-boundary, differential, conformance, and full-stack tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant