From af14a918828e957441abf43bb5a1ea1a5aa35b3b Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Wed, 4 Nov 2026 23:19:13 +0000 Subject: [PATCH 1/9] refactor: replace Materialization with PhysicalProperties (timing, lifetime) Each physical candidate stores PhysicalProperties { timing, lifetime } with Lifetime { None, OneEvaluation(Medium), AcrossEvaluations(Medium) }; PhysicalProperties::new rejects (IngestionTime, OneEvaluation). Plan nodes carry `lifetime` next to their timing; the plan file's node field `materialization` becomes `lifetime` (wire version 12). compatible_timing becomes PhysicalProperties::readable_at with the same truth table. Stage 2 offers the same alternatives as before, one to one with the old variants. Deletes Materialization and its variants, Materialization::timing, is_materialized_view, compatible_timing, and the old export field. Part of #1200 (PR 1 of 2). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- .agents/skills/asap-code-review/SKILL.md | 2 +- crates/accuracy/src/propagation.rs | 6 +- crates/cost/src/execution_demand.rs | 37 ++- crates/cost/src/lib.rs | 4 +- crates/cost/src/usage.rs | 52 +-- crates/cost/tests/held_memory.rs | 31 +- crates/cost/tests/ingestion_refresh_runs.rs | 38 ++- crates/devtools/src/bin/asap_planner.rs | 4 +- crates/devtools/src/candidate_labels.rs | 25 +- crates/devtools/src/planning_stages_text.rs | 10 +- crates/devtools/tests/asap_planner.rs | 22 +- .../devtools/tests/sketch_plan_snapshots.rs | 2 +- crates/executor/src/capability.rs | 2 +- .../executor/src/physical_planner/logical.rs | 2 +- crates/executor/src/physical_planner/mod.rs | 8 +- crates/executor/tests/current_timestamp.rs | 2 +- crates/executor/tests/hydra_cms_execution.rs | 4 +- .../tests/keyed_summary_row_weight.rs | 4 +- crates/executor/tests/physical_dag.rs | 10 +- crates/executor/tests/physical_semantics.rs | 6 +- crates/executor/tests/plan_properties.rs | 2 +- .../executor/tests/precompute_population.rs | 12 +- crates/executor/tests/promql_binary.rs | 4 +- crates/executor/tests/raw_scan.rs | 6 +- .../stored_tumbling_window_memory_limit.rs | 2 +- crates/executor/tests/summary_projection.rs | 8 +- crates/executor/tests/univmon_execution.rs | 2 +- .../executor/tests/weighted_topk_binding.rs | 16 +- crates/integration-tests/src/lib.rs | 22 +- .../tests/deployment_capabilities.rs | 15 +- .../tests/materialization_e2e.rs | 34 +- .../tests/materialized_views.rs | 7 +- .../tests/operator_design_examples.rs | 16 +- .../tests/physical_common/mod.rs | 12 +- .../tests/planner_layering_common/mod.rs | 66 ++-- .../tests/planner_layering_example1.rs | 26 +- .../tests/planner_layering_example4.rs | 54 ++-- .../tests/production_rollup_workloads.rs | 2 +- .../tests/range_evaluation.rs | 37 ++- crates/integration-tests/tests/reuse_rules.rs | 10 +- .../tests/rollup_controlled.rs | 23 +- .../tests/runtime_handoff.rs | 6 +- .../tests/sharing_issue_regressions.rs | 4 +- .../tests/tumbling_window_merge.rs | 29 +- .../src/deployment_capabilities.rs | 6 +- .../src/pass1/memo_population.rs | 2 +- .../src/pass1/per_computation_candidates.rs | 7 +- .../pass1/per_computation_candidates_tests.rs | 4 +- .../src/pass2/memo/rules/reuse.rs | 6 +- .../src/pass2/memo/rules/scan_labels.rs | 2 +- .../rules/shared_configuration_readers.rs | 9 +- .../src/pass2/memo/state_groups.rs | 4 +- .../src/pass2/memo/window_candidates.rs | 4 +- .../src/stage0/cse.rs | 6 +- .../src/test_support.rs | 15 +- .../src/catalog/configurations.rs | 121 ++++--- .../src/catalog/factoring.rs | 4 +- .../src/catalog/inventory.rs | 7 +- .../src/catalog/mod.rs | 5 +- .../src/catalog/pruning.rs | 3 +- .../src/catalog/realize.rs | 34 +- crates/physical-asap-optimization/src/lib.rs | 187 ++++++----- .../src/split_by_timing.rs | 35 +- crates/plan-selection/src/groups.rs | 72 ++--- .../src/groups/accuracy_positions.rs | 4 +- crates/plan-selection/src/groups/tests.rs | 54 ++-- crates/plan-selection/src/lib.rs | 153 +++++---- crates/plan-selection/src/milp/cost_terms.rs | 29 +- crates/plan-selection/src/milp/decode.rs | 4 +- .../plan-selection/src/milp/lp_diagnosis.rs | 4 +- crates/plan-selection/src/milp/model/tests.rs | 50 +-- crates/planner/src/installable.rs | 23 +- crates/planner/src/pass.rs | 2 +- .../tests/deployment_accuracy_model.rs | 3 +- crates/planner/tests/runtime_install.rs | 48 +-- crates/planner/tests/summary_sharing.rs | 5 +- crates/types/src/ir/flat.rs | 6 +- crates/types/src/ir/materialized_view.rs | 32 +- crates/types/src/ir/operator/node.rs | 18 +- .../src/ir/operator/tumbling_window_chain.rs | 12 +- crates/types/src/ir/physical_export.rs | 69 ++-- .../src/ir/properties/execution_data_state.rs | 21 +- crates/types/src/ir/properties/timing.rs | 306 ++++++++++-------- crates/types/src/ir/schema/schema_support.rs | 2 +- crates/types/src/lib.rs | 4 +- crates/types/src/physical/materialization.rs | 57 ---- crates/types/src/physical/mod.rs | 10 +- crates/types/src/physical/properties.rs | 133 ++++++++ crates/types/src/physical/workload_plan.rs | 15 +- .../src/stages/physical/memo_candidates.rs | 28 +- crates/types/src/stages/physical/producers.rs | 6 +- crates/types/src/stages/pruning.rs | 2 +- crates/types/src/stages/realizer.rs | 4 +- crates/types/src/test_support.rs | 6 - crates/types/src/workload/bounds.rs | 2 +- crates/types/tests/materialized_view.rs | 57 +++- crates/types/tests/physical_export.rs | 89 ++--- crates/types/tests/schema_rebuilding.rs | 17 +- crates/types/tests/summary_merge_structure.rs | 5 +- crates/types/tests/tumbling_window_chain.rs | 25 +- .../architecture/physical-plan-integration.md | 6 +- .../architecture/planner-runtime-contract.md | 2 +- docs/design_docs/concepts/glossary.md | 2 +- docs/design_docs/concepts/post-asap-ir.md | 74 +++-- .../physical-planning-and-deployment.md | 21 +- .../design_docs/proposals/planner-layering.md | 43 +-- .../asap-aware-mapping-architecture.md | 8 +- .../asap-aware-mapping-contracts.md | 15 +- .../develop_docs/extend-asap-aware-mapping.md | 5 +- docs/develop_docs/library-api.md | 2 +- docs/develop_docs/pre-asap-ir.md | 6 +- tools/dag-viewer/README.md | 4 +- tools/dag-viewer/app.js | 2 +- tools/dag-viewer/memo.js | 4 +- tools/dag-viewer/stages.js | 4 +- 115 files changed, 1522 insertions(+), 1200 deletions(-) delete mode 100644 crates/types/src/physical/materialization.rs create mode 100644 crates/types/src/physical/properties.rs diff --git a/.agents/skills/asap-code-review/SKILL.md b/.agents/skills/asap-code-review/SKILL.md index 5d6091fcc..bf1b353c1 100644 --- a/.agents/skills/asap-code-review/SKILL.md +++ b/.agents/skills/asap-code-review/SKILL.md @@ -72,7 +72,7 @@ a trade-off, give the author choices here too. For example: - `price` recomputes `query_reach(dag)`, a walk over the whole DAG, for every - MatAtQuery node: O(n · (n + e)) per candidate, times every candidate. At + `OneEvaluation` node: O(n · (n + e)) per candidate, times every candidate. At Example 3's 972 candidates, if each DAG has about 50 nodes, that is about 2.5·10⁶ node visits instead of 5·10⁴. Alternative: compute it once per candidate before the loop and pass it in. diff --git a/crates/accuracy/src/propagation.rs b/crates/accuracy/src/propagation.rs index ed33978df..cace7af85 100644 --- a/crates/accuracy/src/propagation.rs +++ b/crates/accuracy/src/propagation.rs @@ -122,7 +122,7 @@ pub fn root_guarantee(root: &QueryRoot) -> Option { /// Bind known statistics in existing contracts, then recover compositions /// that previously required constant child bounds. Physical state contracts, -/// schemas, timing, materialization, and sharing are preserved. This does not +/// schemas, timing, lifetime, and sharing are preserved. This does not /// infer facts: `bind` must leave unsupported statistics unknown. pub fn bind_guarantees( root: &QueryRoot, @@ -139,7 +139,7 @@ pub fn bind_guarantees( let operator = node.operator.map_children(|child| walk(child, bind, cache)); let mut rebuilt = OperatorNode::with_schema(operator, node.schema.clone()) .with_timing(node.timing) - .with_materialization(node.materialization); + .with_lifetime(node.lifetime); rebuilt.guarantee = node .guarantee .as_ref() @@ -215,7 +215,7 @@ pub fn with_resized_summaries( Rc::new( rebuilt .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } else { node.clone() diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index 6a7e380bd..f2343a1cd 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -9,7 +9,8 @@ use super::analytical::AnalyticalCostError; use asap_types::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; -use asap_types::physical::Materialization; +use asap_types::ir::properties::ExecutionTiming; +use asap_types::physical::Lifetime; use asap_types::workload::{QueryRecurrence, RangeEvaluation, RepeatedDemand}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; @@ -280,7 +281,7 @@ pub fn query_starts(dag: &PhysicalASAPDAG) -> Vec> { .collect() } -/// What computes a `NotMaterialized` node once per its own execution +/// What computes a not-kept node once per its own execution /// ([`consumers`]). #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Consumer { @@ -290,7 +291,7 @@ pub enum Consumer { Materialized(PhysicalASAPNodeId), } -/// The consumers of each `NotMaterialized` node of `dag` that any consumer +/// The consumers of each not-kept node of `dag` that any consumer /// reaches ([`computations`]): the queries and the materialized nodes whose /// walk down their inputs reaches it before meeting a materialized node, /// each once; the queries first, in order, then the materialized nodes in @@ -299,7 +300,7 @@ pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap = dag .nodes .iter() - .filter(|n| n.materialization != Materialization::NotMaterialized) + .filter(|n| n.lifetime.is_kept()) .map(|n| n.id) .collect(); let is_materialized: HashSet = materialized.iter().copied().collect(); @@ -335,17 +336,17 @@ pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap = dag .nodes .iter() - .filter(|n| n.materialization != Materialization::NotMaterialized) - .map(|n| (n.id, n.materialization)) + .filter(|n| n.lifetime.is_kept()) + .map(|n| (n.id, (n.output_state.timing, n.lifetime))) .collect(); let inputs = |id: PhysicalASAPNodeId| { dag.edges @@ -385,14 +386,12 @@ pub fn computations( } } let mut rate_of_materialized = HashMap::new(); - for (&id, materialization) in &materialized { - // A chain kept across evaluations is built once per request. - let per_request = matches!( - materialization, - Materialization::MatAtQueryKeptAcrossEvaluations(_) - ); - let rate = match materialization { - Materialization::MatAtIngestion(_) => 1.0, + for (&id, &(timing, lifetime)) in &materialized { + let at_ingestion = timing == ExecutionTiming::IngestionTime; + // A query-time chain kept across evaluations is built once per request. + let per_request = !at_ingestion && matches!(lifetime, Lifetime::AcrossEvaluations(_)); + let rate = match at_ingestion { + true => 1.0, _ => evaluation_rate( reached.get(&id).into_iter().flatten().filter_map(|&q| { let range = if per_request { None } else { range_of(q) }; @@ -418,7 +417,7 @@ pub fn computations( let refresh_windows = dag.refresh_windows( materialized .iter() - .filter(|(_, m)| matches!(m, Materialization::MatAtIngestion(_))) + .filter(|(_, (timing, _))| *timing == ExecutionTiming::IngestionTime) .map(|(&id, _)| id), ); let mut count: HashMap<_, (u64, f64)> = HashMap::new(); diff --git a/crates/cost/src/lib.rs b/crates/cost/src/lib.rs index d381c59bb..3dc4bac35 100644 --- a/crates/cost/src/lib.rs +++ b/crates/cost/src/lib.rs @@ -80,7 +80,7 @@ pub struct ResourceUsage { pub average_memory_bytes: f64, /// The most memory live at once, assuming every evaluation overlaps: /// in-memory kept state plus each computation's working memory, once - /// per consumer that recomputes it, with the `MatAtIngestion` consumers + /// per consumer that recomputes it, with the consumers kept at ingestion time /// of one refresh window counted once. pub peak_memory_bytes: u64, /// Bytes kept on disk: state materialized on `Medium::Disk`, plus the @@ -375,7 +375,7 @@ pub struct NodeCost { /// node the query reads first. pub cpu_core_seconds_per_second: f64, /// The number of consumers it is computed for, with the - /// `MatAtIngestion` consumers of one refresh window counted once (1 + /// consumers kept at ingestion time of one refresh window counted once (1 /// when materialized, [`execution_demand::computations`]). pub multiplier: u64, /// How it was measured, e.g. "scan 1000 samples; x 1.0000/s; keeps diff --git a/crates/cost/src/usage.rs b/crates/cost/src/usage.rs index f811145d4..e14c672ab 100644 --- a/crates/cost/src/usage.rs +++ b/crates/cost/src/usage.rs @@ -30,7 +30,7 @@ use asap_types::ir::schema::{ FieldDataType, GroupingStrategy, Schema, SketchParams, SketchStatistic, }; use asap_types::ir::{ASAPOp, NonASAPOp, TimeRangeKind}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium}; use asap_types::workload::{DataWorkload, QueryRecurrence, RangeEvaluation}; use asap_types::workload::bounds::{ @@ -94,8 +94,8 @@ pub fn plan_cost( // Each node's work in ms on one core: one computation at query time, // one second of arriving rows at ingestion time. let mut work_ms: HashMap = HashMap::new(); - // Query-time memory held only while one evaluation runs, a MatAtQuery - // state in memory or a NotMaterialized node's working memory: (bytes, + // Query-time memory held only while one evaluation runs, a OneEvaluation + // state in memory or a not-kept node's working memory: (bytes, // per second, whether each consumer computes its own copy), // counted once the evaluations' latencies are known, in node order so // the sum is the same in every run. @@ -246,13 +246,13 @@ pub fn plan_cost( for (latency, evaluation_ms) in latency.iter_mut().zip(evaluation_ms_per_query) { latency.query_ms += evaluation_ms; } - // Query-time memory is held for one evaluation: a MatAtQuery state from + // Query-time memory is held for one evaluation: a `OneEvaluation` state from // its build until the longest query reading it finishes, about that - // query's latency, once per execution. A NotMaterialized node's working + // query's latency, once per execution. A not-kept node's working // memory is computed once per consumer ([`consumers`]), and each copy is // held while its consumer's evaluation runs: a query's for that query's // latency, at its rate; a materialized node's until the longest query - // reading that node finishes, at the node's rate, as its MatAtQuery + // reading that node finishes, at the node's rate, as its `OneEvaluation` // state is. let longest_reader_ms = |id: PhysicalASAPNodeId| { reach @@ -957,13 +957,13 @@ pub fn node_usage<'a>( // query time (all of them for a chain kept across // evaluations, whose scan Stage 2 bounds to its newest tumbling window, // the only one it builds). - let rows_per_tumbling_window = match (ingestion, node.materialization) { + let rows_per_tumbling_window = match (ingestion, node.lifetime) { (true, _) => u64::try_from( (u128::from(input.rows) * u128::from(*tumbling_window_width_ms)) .div_ceil(1_000), ) .map_err(|_| AnalyticalCostError::Overflow)?, - (false, Materialization::MatAtQueryKeptAcrossEvaluations(_)) => input.rows, + (false, Lifetime::AcrossEvaluations(_)) => input.rows, (false, _) => input .rows .div_ceil(u64::from(*tumbling_window_count).max(1)), @@ -1128,10 +1128,10 @@ pub fn node_usage<'a>( // consumer that recomputes it; at query time, that is held for the // evaluation too (counted in [`plan_cost`], per consumer: a query's // latency, or a materialized consumer's longest reader's, as a - // MatAtQuery state is). + // OneEvaluation state is). let state = out.bytes.max(estimate.peak_memory_bytes()); - let (kept, medium) = match (node.materialization, &node.payload) { - (Materialization::NotMaterialized, _) => { + let (kept, medium) = match (ingestion, node.lifetime, &node.payload) { + (_, Lifetime::None, _) => { let working_memory_bytes = estimate.peak_memory_bytes(); peak_memory_bytes = working_memory_bytes.saturating_mul(multiplier); if !ingestion && working_memory_bytes > 0 { @@ -1143,7 +1143,11 @@ pub fn node_usage<'a>( // retention covers ([`tumbling_window_retention_ms`]: N, plus one per tumbling window // width of the readers' range-evaluation span), all but the // newest between evaluations and all while one runs. - (Materialization::MatAtQueryKeptAcrossEvaluations(medium), _) => { + ( + false, + Lifetime::AcrossEvaluations(medium), + Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), + ) => { let tumbling_windows = tumbling_windows_of(node); let retained = retained_tumbling_window_count; let between = (state / tumbling_windows) @@ -1168,7 +1172,7 @@ pub fn node_usage<'a>( detail += &format!("; keeps {between} bytes across evaluations"); (0, medium) } - (Materialization::MatAtQuery(medium), _) => { + (_, Lifetime::OneEvaluation(medium), _) => { match medium { Medium::Memory => { held = Some((state, per_second, false)); @@ -1180,7 +1184,8 @@ pub fn node_usage<'a>( } // The retained tumbling windows and the one being built. ( - Materialization::MatAtIngestion(medium), + true, + Lifetime::AcrossEvaluations(medium), Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), ) => { let tumbling_windows = tumbling_windows_of(node); @@ -1195,12 +1200,13 @@ pub fn node_usage<'a>( medium, ) } - (Materialization::MatAtIngestion(medium), _) => ( + // A whole state kept across evaluations: it and the one being built. + (_, Lifetime::AcrossEvaluations(medium), _) => ( state.checked_mul(2).ok_or(AnalyticalCostError::Overflow)?, medium, ), }; - if node.materialization == Materialization::MatAtIngestion(Medium::Memory) { + if ingestion && node.lifetime == Lifetime::AcrossEvaluations(Medium::Memory) { maintained = Some(state / tumbling_windows_of(node)); } if kept > 0 { @@ -1399,7 +1405,7 @@ pub fn tumbling_window_retention_ms( let nodes = node_map(dag); dag.nodes .iter() - .filter_map(|node| match (&node.payload, node.materialization) { + .filter_map(|node| match (&node.payload, node.lifetime) { ( Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { child, @@ -1407,8 +1413,7 @@ pub fn tumbling_window_retention_ms( tumbling_window_count, .. }), - Materialization::MatAtIngestion(_) - | Materialization::MatAtQueryKeptAcrossEvaluations(_), + Lifetime::AcrossEvaluations(_), ) => { let span_ms = reach .iter() @@ -1594,8 +1599,8 @@ pub fn node_map(dag: &PhysicalASAPDAG) -> NodeMap<'_> { pub type NodeMap<'a> = HashMap; -/// The tumbling-window chains of `dag` kept across evaluations -/// (`MatAtQueryKeptAcrossEvaluations`, which Stage 2 offers only when the +/// The query-time tumbling-window chains of `dag` kept across evaluations +/// (lifetime `AcrossEvaluations` at query time, which Stage 2 offers only when the /// deployment keeps query-time results and every reader builds one new /// tumbling window per evaluation). Each evaluation builds the newest tumbling window, and the /// older ones, which complete the readers' look-back, are kept from @@ -1605,10 +1610,11 @@ pub fn kept_tumbling_window_chains(dag: &PhysicalASAPDAG) -> HashSet Vec<(usize, f64, f64)> { .collect() } -fn materialization_of(dag: &PhysicalASAPDAG, id: usize) -> Materialization { - dag.nodes - .iter() - .find(|n| n.id == id) - .unwrap() - .materialization +fn lifetime_of(dag: &PhysicalASAPDAG, id: usize) -> Lifetime { + dag.nodes.iter().find(|n| n.id == id).unwrap().lifetime } fn close(a: f64, b: f64) -> bool { @@ -98,9 +94,9 @@ fn close(a: f64, b: f64) -> bool { /// Query 0 is `sum(...)` over query 1's output, so it runs longer. Without /// a materialized node, each query computes the shared nodes and holds /// their working memory for its own latency: `bytes · Σ rate_q · latency_q`. -/// When query 1's output is `MatAtQuery`, the nodes below it are computed +/// When query 1's output is `OneEvaluation`, the nodes below it are computed /// once per execution of it, at its rate, and held until the -/// longest reader, query 0, finishes, as the `MatAtQuery` state itself is: +/// longest reader, query 0, finishes, as the `OneEvaluation` state itself is: /// `bytes · rate · latency_0`, not the rate-weighted mean of the two /// latencies. #[test] @@ -115,15 +111,15 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { false, ) .unwrap(); - let dag_with = |materialization: Materialization| { + let dag_with = |lifetime: Lifetime| { plans .iter() .map(|plan| &plan.dag) - .find(|dag| materialization_of(dag, dag.roots[1]) == materialization) + .find(|dag| lifetime_of(dag, dag.roots[1]) == lifetime) .unwrap() }; - let recomputed = dag_with(Materialization::NotMaterialized); - let shared = dag_with(Materialization::MatAtQuery(Medium::Memory)); + let recomputed = dag_with(Lifetime::None); + let shared = dag_with(Lifetime::OneEvaluation(Medium::Memory)); let latency_ms = |dag| { let cost = cost(dag, 1.0); [0, 1].map(|q| cost.usage.latency_per_query[q].total_ms()) @@ -146,7 +142,7 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { assert!(close(term, expected), "node {id}: {term} vs {expected}"); } - // Below a MatAtQuery node: the longest reader's latency at the + // Below a `OneEvaluation` node: the longest reader's latency at the // materialized node's rate (its readers' schedules together). let materialized_rate = evaluation_rate( recurrence().iter().map(|r| (r, None)), @@ -158,10 +154,7 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { let checked = below(shared); assert!(!checked.is_empty(), "the nodes below it hold memory"); for (id, bytes, term) in checked { - assert_eq!( - materialization_of(shared, id), - Materialization::NotMaterialized - ); + assert_eq!(lifetime_of(shared, id), Lifetime::None); let expected = bytes * materialized_rate * outer_ms / 1_000.0; assert!(close(term, expected), "node {id}: {term} vs {expected}"); } diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index ebd33bab5..1751a7d87 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -1,4 +1,4 @@ -//! How often a `NotMaterialized` node is computed for the views refreshed +//! How often a not-kept node is computed for the views refreshed //! at ingestion above it ([`computations`]): once per refresh window, since //! a runtime refreshes the views of one refresh window in one ingestion run //! (issue #1151). @@ -9,6 +9,7 @@ use std::time::Duration; use asap_cost::execution_demand::computations; use asap_types::ir::operator::operator_properties::{Reduction, Source, TimeShift}; use asap_types::ir::physical_export::{compile_physical_asap_workload, PhysicalASAPDAG}; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::{ DataType, Field, FieldDataType, GroupingStrategy, Schema, SketchAlgorithm, SketchKind, @@ -18,7 +19,7 @@ use asap_types::ir::{ apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, NonASAPOp, Operator, OperatorNode, QueryRoot, TimeRangeKind, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::workload::{QueryRecurrence, RepeatedDemand, RepetitionInterval}; /// `m` with columns `ts`, `value` and `job`. @@ -73,15 +74,15 @@ fn chain( } /// One query per summary of `summaries`, merging it, with each summary -/// materialized as `materialization`: the DAG Stage 3 costs, chains +/// kept with `kept` (`None`: not kept): the DAG Stage 3 costs, chains /// unexpanded. -fn dag_of(summaries: &[Rc], materialization: Materialization) -> PhysicalASAPDAG { +fn dag_of(summaries: &[Rc], kept: Option) -> PhysicalASAPDAG { let mut assignment = MaterializationAssignment::default(); let roots: Vec = summaries .iter() .map(|summary| { - if materialization != Materialization::NotMaterialized { - assignment.set(summary, materialization); + if kept.is_some() { + assignment.set(summary, kept); } QueryRoot::Operator( OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryMerge { @@ -132,7 +133,14 @@ fn shifted(child: &Rc, offset_ms: i64) -> Rc { .unwrap() } -const AT_INGESTION: Materialization = Materialization::MatAtIngestion(Medium::Memory); +/// Kept at ingestion time until a query reads it. +fn at_ingestion() -> Option { + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok() +} /// A KLL chain and a DDSketch chain of 10 s tumbling windows over one `Scan`, both /// kept at ingestion, are refreshed in one ingestion run per tumbling window: the @@ -145,7 +153,7 @@ fn a_scan_under_two_chains_of_one_tumbling_window_width_is_computed_once() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!(scan_computations(&dag), (1, 1.0)); } @@ -161,13 +169,13 @@ fn a_scan_under_chains_of_two_tumbling_window_widths_is_computed_for_each() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 60_000, 5), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } /// Query consumers are unchanged: with both chains built at query time -/// (`NotMaterialized`), each query computes the `Scan` at its own rate. +/// (not kept), each query computes the `Scan` at its own rate. #[test] fn query_consumers_still_count_once_each() { let scan = scan(); @@ -195,7 +203,7 @@ fn query_consumers_still_count_once_each() { build(range(60_000), SketchAlgorithm::Kll), build(range(60_000), SketchAlgorithm::DDSketch), ], - Materialization::NotMaterialized, + None, ); assert_eq!(scan_computations(&dag), (2, 0.2)); } @@ -211,7 +219,7 @@ fn a_scan_under_chains_of_10_10_and_60_s_is_computed_for_each_width() { chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), chain(&scan, SketchAlgorithm::Kll, 60_000, 5), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -231,7 +239,7 @@ fn chains_of_one_width_and_two_phases_are_computed_apart() { 30, ), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -246,7 +254,7 @@ fn nodes_below_a_shared_intermediate_node_are_computed_once_per_run() { chain(&shift, SketchAlgorithm::Kll, 10_000, 6), chain(&shift, SketchAlgorithm::DDSketch, 10_000, 30), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!(scan_computations(&dag), (1, 1.0)); assert_eq!( @@ -280,7 +288,7 @@ fn consumers_of_unbounded_windows_count_alone() { build(SketchAlgorithm::Kll), build(SketchAlgorithm::DDSketch), ], - AT_INGESTION, + at_ingestion(), ); assert_eq!( computations_of(&dag, |op| matches!(op, NonASAPOp::Values { .. })), diff --git a/crates/devtools/src/bin/asap_planner.rs b/crates/devtools/src/bin/asap_planner.rs index 4e231d027..916daa183 100644 --- a/crates/devtools/src/bin/asap_planner.rs +++ b/crates/devtools/src/bin/asap_planner.rs @@ -731,8 +731,8 @@ fn stage2_pruned_candidates_json(stage2: Option<&PhysicalASAPMemoCandidates>) -> "operator_node": key.operator_node.0, "operator": flat.nodes.last().map(node_label).unwrap_or_default(), "implementation_root": node.is_implementation_root, - "timing": key.timing, - "materialization": key.materialization, + "timing": key.properties.timing(), + "lifetime": key.properties.lifetime(), "reason": format!("{:?}", pruned.reason), }) }) diff --git a/crates/devtools/src/candidate_labels.rs b/crates/devtools/src/candidate_labels.rs index 87ef5d797..8164b3025 100644 --- a/crates/devtools/src/candidate_labels.rs +++ b/crates/devtools/src/candidate_labels.rs @@ -10,10 +10,11 @@ use std::rc::Rc; use serde_json::Value; use asap_types::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm}; use asap_types::ir::NonASAPOp; use asap_types::ir::{ASAPOp, Operator, OperatorNode, QueryRoot}; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use asap_types::physical::PhysicalWorkloadPlan; use asap_types::stages::HowToComputeAggregateMeasure; @@ -144,19 +145,19 @@ fn duration_name(ms: u64) -> String { /// just `logical` when nothing is. pub fn physical_label(logical: &str, candidate: &PhysicalWorkloadPlan) -> String { let mut parts: Vec<(&str, Vec)> = Vec::new(); - for (id, materialization) in &candidate.materialization { - let phase = match materialization { - Materialization::NotMaterialized => continue, - Materialization::MatAtIngestion(_) => "ingestion time", - Materialization::MatAtQuery(_) => "query time, shared", - Materialization::MatAtQueryKeptAcrossEvaluations(_) => "query time, kept", - }; + for (id, lifetime) in &candidate.lifetime { let node = candidate .dag .nodes .iter() .find(|n| n.id == *id) .expect("an assigned node is in the DAG"); + let phase = match (node.output_state.timing, lifetime) { + (_, Lifetime::None) => continue, + (ExecutionTiming::IngestionTime, _) => "ingestion time", + (ExecutionTiming::QueryTime, Lifetime::OneEvaluation(_)) => "query time, shared", + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => "query time, kept", + }; let label = match &node.payload { // Name the chain: chains of one family and tumbling-window count differ by // their readers and tumbling-window width. @@ -495,10 +496,12 @@ mod tests { let one_chain_at_ingestion: Vec = plans .iter() .filter(|plan| { - plan.materialization + plan.lifetime .iter() - .filter(|(id, m)| { - matches!(m, Materialization::MatAtIngestion(_)) + .filter(|(id, lifetime)| { + let node = plan.dag.nodes.iter().find(|n| n.id == **id).unwrap(); + lifetime.is_kept() + && node.output_state.timing == ExecutionTiming::IngestionTime && matches!( plan.dag .nodes diff --git a/crates/devtools/src/planning_stages_text.rs b/crates/devtools/src/planning_stages_text.rs index f68332018..7ae4d92ab 100644 --- a/crates/devtools/src/planning_stages_text.rs +++ b/crates/devtools/src/planning_stages_text.rs @@ -370,8 +370,8 @@ fn write_physical(out: &mut String, physical: &PhysicalASAPMemoCandidates) { vec![ format!("C{id}:"), format!("O{}", candidate.operator_node.0), - format!("{:?}", candidate.timing), - format!("{:?}", candidate.materialization), + format!("{:?}", candidate.properties.timing()), + format!("{:?}", candidate.properties.lifetime()), // It may produce a query's output. if candidate.may_produce_query_output { "output".to_owned() @@ -414,8 +414,8 @@ fn write_physical(out: &mut String, physical: &PhysicalASAPMemoCandidates) { vec![ format!("G{}", pruned.group.0), format!("O{}", key.operator_node.0), - format!("{:?}", key.timing), - format!("{:?}", key.materialization), + format!("{:?}", key.properties.timing()), + format!("{:?}", key.properties.lifetime()), format!("{:?}", pruned.reason), ] }) @@ -608,7 +608,7 @@ mod tests { // Stage 2 offers the tumbling-window chain at ingestion time, read from the // ingestion-time scan. assert!( - has_line(&["IngestionTime MatAtIngestion(Memory)", "<- {C1}"]), + has_line(&["IngestionTime AcrossEvaluations(Memory)", "<- {C1}"]), "{text}" ); assert!( diff --git a/crates/devtools/tests/asap_planner.rs b/crates/devtools/tests/asap_planner.rs index 5f655d3b2..3feeb906f 100644 --- a/crates/devtools/tests/asap_planner.rs +++ b/crates/devtools/tests/asap_planner.rs @@ -1112,8 +1112,9 @@ fn workload_file_with_a_range_evaluation_is_planned() { tumbling_window_candidates, window_composition_pass2_candidates, }; use asap_types::ir::physical_export::PhysicalASAPOperatorPayload; + use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::ASAPOp; - use asap_types::physical::{Materialization, Medium}; + use asap_types::physical::{Lifetime, Medium}; let parsed: PlanningWorkload = serde_json::from_value(workload.clone()).unwrap(); let entries: Vec<_> = parsed.query_workload.entries().collect(); let data = parsed.data_workload.clone().unwrap(); @@ -1149,8 +1150,8 @@ fn workload_file_with_a_range_evaluation_is_planned() { matches!( n.payload, PhysicalASAPOperatorPayload::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) - ) && n.materialization - == Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory) + ) && n.output_state.timing == ExecutionTiming::QueryTime + && n.lifetime == Lifetime::AcrossEvaluations(Medium::Memory) }) }) .expect("a plan keeps its tumbling windows across evaluations"); @@ -1578,7 +1579,8 @@ fn scans_projecting_different_labels_are_shared() { let data = workload.data_workload.as_ref().unwrap(); let roots = lower_promql_roots(&workload).unwrap(); use asap_logical_asap_optimization::test_support::with_union_scan_labels; - use asap_types::physical::{Materialization, Medium}; + use asap_types::ir::properties::ExecutionTiming; + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; // Plans `roots` with identical sub-DAGs made one node, as the memo's // groups are, and a node read by several roots kept for the evaluation. let plan = |name: &str, roots: &[QueryRoot]| { @@ -1602,11 +1604,13 @@ fn scans_projecting_different_labels_are_shared() { data, false, &mut |readers| { - Some(if readers.len() > 1 { - Materialization::MatAtQuery(Medium::Memory) - } else { - Materialization::NotMaterialized - }) + Some((readers.len() > 1).then(|| { + PhysicalProperties::new( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ) + .unwrap() + })) }, ) .unwrap() diff --git a/crates/devtools/tests/sketch_plan_snapshots.rs b/crates/devtools/tests/sketch_plan_snapshots.rs index e3c9d1be5..1ab0097d1 100644 --- a/crates/devtools/tests/sketch_plan_snapshots.rs +++ b/crates/devtools/tests/sketch_plan_snapshots.rs @@ -6,7 +6,7 @@ //! queries or nested windows, answer a ratio of two quantiles from one tumbling window //! chain, and materialize tumbling windows, under the MVP deployment (raw data not //! retained) and raw data retained. A change to sketch kinds, parameters, -//! sizes, sharing, timing, materialization or cost shows up as a snapshot +//! sizes, sharing, timing, lifetime or cost shows up as a snapshot //! diff. //! //! `tests/sketch_plan_snapshots/manifest.json` lists each workload by id: diff --git a/crates/executor/src/capability.rs b/crates/executor/src/capability.rs index f7a2e3afd..0885391de 100644 --- a/crates/executor/src/capability.rs +++ b/crates/executor/src/capability.rs @@ -230,7 +230,7 @@ pub(crate) fn hydra_cms_shape( /// none of the query's columns for the filter predicate to read, so only a /// query-time build can apply it. The ingestion-time compiler and the /// binding of any ingestion-timed `SummaryAgg` apply this check. The planner -/// applies the same rule: Stage 2 never offers `MatAtIngestion` for a +/// applies the same rule: Stage 2 never offers keeping at ingestion time for a /// filtered build (`IngestionPruneReason::Filtered`), and materialization /// timing rejects an explicit one (`FilteredSummaryAtIngestion`). This check /// guards plans that did not come from the planner. diff --git a/crates/executor/src/physical_planner/logical.rs b/crates/executor/src/physical_planner/logical.rs index fc4f78c91..774a38843 100644 --- a/crates/executor/src/physical_planner/logical.rs +++ b/crates/executor/src/physical_planner/logical.rs @@ -37,7 +37,7 @@ pub(super) fn restore(dag: &PhysicalASAPDAG) -> Result>) -> PhysicalASAPDAG { }, ), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: schema(), guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/hydra_cms_execution.rs b/crates/executor/tests/hydra_cms_execution.rs index 7502bc10d..9d5e8185c 100644 --- a/crates/executor/tests/hydra_cms_execution.rs +++ b/crates/executor/tests/hydra_cms_execution.rs @@ -17,7 +17,7 @@ use planner_types::ir::scalar::{ColumnRef, CompareOpKind, ScalarValue}; use planner_types::ir::schema::DataType; use planner_types::ir::schema::*; use planner_types::ir::{ASAPOp, ExprSemantics, Predicate, ScalarExpr}; -use planner_types::physical::Materialization; +use planner_types::physical::Lifetime; use std::{collections::BTreeMap, sync::Arc}; const WIDTH: u32 = 64; @@ -75,7 +75,7 @@ fn node(id: usize, payload: Payload, output: Schema) -> PhysicalASAPDAGNode { id, payload, output_state: ExecutionDataState::QUERY_ROWS, - materialization: Materialization::NotMaterialized, + lifetime: Lifetime::None, output_schema: output, guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/keyed_summary_row_weight.rs b/crates/executor/tests/keyed_summary_row_weight.rs index 91f8bf032..f5167ad63 100644 --- a/crates/executor/tests/keyed_summary_row_weight.rs +++ b/crates/executor/tests/keyed_summary_row_weight.rs @@ -17,7 +17,7 @@ use planner_types::ir::properties::ExecutionDataState; use planner_types::ir::scalar::ColumnRef; use planner_types::ir::schema::*; use planner_types::ir::ASAPOp; -use planner_types::physical::Materialization; +use planner_types::physical::Lifetime; use std::sync::Arc; /// `(job, service)` rows: jobs are the groups, services the items. @@ -159,7 +159,7 @@ fn query_time_count_heap_binds_a_constant_row_weight() { filter: None, }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Materialization::NotMaterialized, + lifetime: Lifetime::None, output_schema: (*schema(vec![ Field::plain("job", DataType::Utf8, false), Field { diff --git a/crates/executor/tests/physical_dag.rs b/crates/executor/tests/physical_dag.rs index bd22b97d5..6a99cc033 100644 --- a/crates/executor/tests/physical_dag.rs +++ b/crates/executor/tests/physical_dag.rs @@ -539,7 +539,7 @@ fn bind_physical_asap_dag_before_execution() { id, payload, output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*schema).clone(), guarantee: None, retention_ms: None, @@ -700,7 +700,7 @@ fn planner_semijoin_sort_limit_contract_at_both_phases() { payload, output_schema: (**schema).clone(), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, }; @@ -1136,7 +1136,7 @@ fn grouped_temporal_schema_compiles_and_executes_topk() { id, payload, output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*input).clone(), guarantee: None, retention_ms: None, @@ -1226,7 +1226,7 @@ fn certified_pruning_rejects_missing_authoritative_values_after_recovery() { id: 2, output_schema: (*schema).clone(), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, payload: PhysicalASAPOperatorPayload::NonASAP(planner_types::ir::NonASAPOp::Join { @@ -1331,7 +1331,7 @@ fn compiled_ingestion_binary_preserves_alignment_and_rejects_missing_updates() { id: 2, output_schema: (*input).clone(), output_state: ExecutionDataState::INGESTION_ROWS, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, payload: PhysicalASAPOperatorPayload::NonASAP(planner_types::ir::NonASAPOp::BinaryOp { diff --git a/crates/executor/tests/physical_semantics.rs b/crates/executor/tests/physical_semantics.rs index 2831befe1..418b5c8bb 100644 --- a/crates/executor/tests/physical_semantics.rs +++ b/crates/executor/tests/physical_semantics.rs @@ -385,7 +385,7 @@ fn global_extrema_bind_with_planner_derived_schema() { child: 0, }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*output).clone(), guarantee: None, retention_ms: None, @@ -935,7 +935,7 @@ fn planner_node( id: 1, payload, output_state: planner_types::ir::properties::ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: planner_types::ir::schema::Schema::new( fields .iter() @@ -1192,7 +1192,7 @@ fn exact_aggregate_node( child: 0, }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*schema(&[(name, dtype, false)])).clone(), guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/plan_properties.rs b/crates/executor/tests/plan_properties.rs index 3b664a12a..6fedc7157 100644 --- a/crates/executor/tests/plan_properties.rs +++ b/crates/executor/tests/plan_properties.rs @@ -49,7 +49,7 @@ fn sorted_scan(schema: &Schema, identity: &Source) -> PhysicalASAPDAG { id, payload, output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: schema.clone(), guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/precompute_population.rs b/crates/executor/tests/precompute_population.rs index 81e9b58cb..b5599d7cb 100644 --- a/crates/executor/tests/precompute_population.rs +++ b/crates/executor/tests/precompute_population.rs @@ -30,7 +30,7 @@ fn logical_schema(family: FieldDataType) -> Schema { time_index: None, } } -/// The stored state at node 0 (`MatAtIngestion`): a global `family` +/// The stored state at node 0 (kept at ingestion time): a global `family` /// `SummaryAgg` over a minute of raw `m` samples (`Scan` node `scan`, /// `TimeRange` node `scan + 1`). fn view_over_samples( @@ -50,14 +50,14 @@ fn view_over_samples( id, payload, output_state, - materialization: Default::default(), + lifetime: Default::default(), output_schema, guarantee: None, retention_ms: None, }; [ PhysicalASAPDAGNode { - materialization: planner_types::physical::Materialization::MatAtIngestion( + lifetime: planner_types::physical::Lifetime::AcrossEvaluations( planner_types::physical::Medium::Memory, ), ..node( @@ -137,7 +137,7 @@ fn try_state_dag( group_by: None, }), output_state: ExecutionDataState::INGESTION_SUMMARY, - materialization: planner_types::physical::Materialization::MatAtIngestion( + lifetime: planner_types::physical::Lifetime::AcrossEvaluations( planner_types::physical::Medium::Memory, ), output_schema: logical_schema(family.clone()), @@ -152,7 +152,7 @@ fn try_state_dag( child: read_id - 1, }), output_state: ExecutionDataState::INGESTION_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: logical_schema(FieldDataType::Plain(DataType::Float64)), guarantee: None, retention_ms: None, @@ -169,7 +169,7 @@ fn try_state_dag( child: read_id, }), output_state: ExecutionDataState::INGESTION_SUMMARY, - materialization: planner_types::physical::Materialization::MatAtIngestion( + lifetime: planner_types::physical::Lifetime::AcrossEvaluations( planner_types::physical::Medium::Memory, ), output_schema: logical_schema(target), diff --git a/crates/executor/tests/promql_binary.rs b/crates/executor/tests/promql_binary.rs index 8bff8a966..8a7bb9fc6 100644 --- a/crates/executor/tests/promql_binary.rs +++ b/crates/executor/tests/promql_binary.rs @@ -81,7 +81,7 @@ fn program_for_bool(operator: BinaryOperator, return_bool: bool) -> Operator { rhs: 1, }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*schema).clone(), guarantee: None, retention_ms: None, @@ -416,7 +416,7 @@ fn stored_series_evaluations_support_filters_and_sets() { 5 | 6 => ExecutionDataState::QUERY_ROWS, _ => ExecutionDataState::QUERY_ROWS, }, - materialization: Default::default(), + lifetime: Default::default(), output_schema: match id { 0 | 1 => (*state_schema).clone(), 5 | 6 => sample_schema(), diff --git a/crates/executor/tests/raw_scan.rs b/crates/executor/tests/raw_scan.rs index 5cdafc837..8d8379714 100644 --- a/crates/executor/tests/raw_scan.rs +++ b/crates/executor/tests/raw_scan.rs @@ -84,7 +84,7 @@ fn plan( id, payload, output_state: state, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (**schema).clone(), guarantee: None, retention_ms: None, @@ -504,7 +504,7 @@ fn windowed_plan(shift_ms: Option) -> PhysicalASAPDAG { id, payload: PhysicalASAPOperatorPayload::NonASAP(payload), output_state: state, - materialization: Default::default(), + lifetime: Default::default(), output_schema: schema.clone(), guarantee: None, retention_ms: None, @@ -837,7 +837,7 @@ fn windowed_count_plan(shift_ms: Option) -> PhysicalASAPDAG { id, payload, output_state, - materialization: Default::default(), + lifetime: Default::default(), output_schema: output_schema.clone(), guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/stored_tumbling_window_memory_limit.rs b/crates/executor/tests/stored_tumbling_window_memory_limit.rs index 350e66212..1fd8c236b 100644 --- a/crates/executor/tests/stored_tumbling_window_memory_limit.rs +++ b/crates/executor/tests/stored_tumbling_window_memory_limit.rs @@ -328,7 +328,7 @@ fn merge_over_a_stored_tumbling_window( payload, output_schema: output_schema.clone(), output_state, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, }; diff --git a/crates/executor/tests/summary_projection.rs b/crates/executor/tests/summary_projection.rs index 392568d84..46331f3cf 100644 --- a/crates/executor/tests/summary_projection.rs +++ b/crates/executor/tests/summary_projection.rs @@ -52,7 +52,7 @@ fn raw_node(id: usize, payload: NonASAPOp) -> PhysicalASAPDAGNode { payload: PhysicalASAPOperatorPayload::NonASAP(payload), output_schema: sample_schema(), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, } @@ -123,7 +123,7 @@ fn summary_projection_survives_recovery() { }), output_schema: (*schema).clone(), output_state: ExecutionDataState::INGESTION_SUMMARY, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, }, @@ -151,7 +151,7 @@ fn summary_projection_survives_recovery() { }), output_schema: output.clone(), output_state: ExecutionDataState::INGESTION_SUMMARY, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, }, @@ -259,7 +259,7 @@ fn summary_merge_without_inputs_is_rejected() { }), output_schema: schema, output_state: ExecutionDataState::INGESTION_SUMMARY, - materialization: Default::default(), + lifetime: Default::default(), guarantee: None, retention_ms: None, }], diff --git a/crates/executor/tests/univmon_execution.rs b/crates/executor/tests/univmon_execution.rs index 5533e6c31..d77d82b7c 100644 --- a/crates/executor/tests/univmon_execution.rs +++ b/crates/executor/tests/univmon_execution.rs @@ -191,7 +191,7 @@ fn planner_unit_frequency_update_binds_as_a_value_frequency_build() -> Result<() filter: None, }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Default::default(), + lifetime: Default::default(), output_schema: (*state).clone(), guarantee: None, retention_ms: None, diff --git a/crates/executor/tests/weighted_topk_binding.rs b/crates/executor/tests/weighted_topk_binding.rs index eacadcca7..e3d23aa45 100644 --- a/crates/executor/tests/weighted_topk_binding.rs +++ b/crates/executor/tests/weighted_topk_binding.rs @@ -126,7 +126,7 @@ fn assert_weighted_binding(algorithm: SketchAlgorithm) { }) .collect(); let batch = Batch::try_new(samples.clone(), rows).unwrap(); - // The summaries `MatAtIngestion` run as data arrives; `NotMaterialized` + // The summaries kept at ingestion time run as data arrives; not kept // (the default) runs everything when the query does. for (placed, scope) in [ ( @@ -267,17 +267,18 @@ fn rate_updates_cannot_enter_integer_heap_factory() { .is_err()); } -/// `candidate` with every `SummaryAgg` `MatAtIngestion`, the materialization +/// `candidate` with every `SummaryAgg` kept at ingestion time, the materialization /// a continuously served query would get: each summary and every input it /// consumes run at ingestion time, the rest at query time. The candidate pins /// its finalize boundary to query time, which would put the summaries above /// it upstream of a query-time node, so the pin is lifted first. fn continuously_maintained_dag(candidate: &Rc) -> PhysicalASAPDAG { + use planner_types::ir::properties::ExecutionTiming; use planner_types::ir::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, Operator as IrOperator, OperatorNode, }; - use planner_types::physical::{Materialization, Medium}; + use planner_types::physical::{Lifetime, Medium, PhysicalProperties}; fn unpinned(node: &Rc) -> Rc { let mut copy = (**node).clone(); copy.operator = node.operator.map_children(unpinned); @@ -293,7 +294,14 @@ fn continuously_maintained_dag(candidate: &Rc) let mut assignment = MaterializationAssignment::default(); for node in OperatorNode::reachable(&candidate) { if matches!(node.operator, IrOperator::ASAP(ASAPOp::SummaryAgg { .. })) { - assignment.set(&node, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + &node, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); } } let timed = diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs index 49534547c..104a1f28e 100644 --- a/crates/integration-tests/src/lib.rs +++ b/crates/integration-tests/src/lib.rs @@ -98,26 +98,32 @@ pub mod fixtures { /// Timing and physical ASAP DAG export helpers for planned candidates. pub mod physical_export { use asap_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAPDAG}; + use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, OperatorNode, }; - use asap_types::physical::{Materialization, Medium}; + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; - /// Time `root` under the default assignment (every sub-DAG - /// `NotMaterialized`, so every summary computed at query time). Returns the timed copy; read `node.timing` on it. + /// Time `root` under the default assignment (no sub-DAG kept, so every + /// summary computed at query time). Returns the timed copy; read `node.timing` on it. pub fn timed(root: &Rc) -> Rc { timed_with(root, &MaterializationAssignment::default()) } - /// Time `root` with every sub-DAG `MatAtIngestion` where the DAG allows it. + /// Time `root` with every sub-DAG kept at ingestion time where the DAG + /// allows it. pub fn at_ingestion(root: &Rc) -> Rc { timed_with( root, - &MaterializationAssignment::with_default(Materialization::MatAtIngestion( - Medium::Memory, - )), + &MaterializationAssignment::with_default( + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ), ) } @@ -134,7 +140,7 @@ pub mod physical_export { compile_physical_asap_dag(&timed(root)).expect("physical ASAP DAG export failed") } - /// Time `root` with every sub-DAG `MatAtIngestion` where the DAG allows + /// Time `root` with every sub-DAG kept at ingestion time where the DAG allows /// it, then export the physical DAG. pub fn at_ingestion_physical_asap_dag(root: &Rc) -> PhysicalASAPDAG { compile_physical_asap_dag(&at_ingestion(root)).expect("physical ASAP DAG export failed") diff --git a/crates/integration-tests/tests/deployment_capabilities.rs b/crates/integration-tests/tests/deployment_capabilities.rs index 482ca9ac5..4982a8d7d 100644 --- a/crates/integration-tests/tests/deployment_capabilities.rs +++ b/crates/integration-tests/tests/deployment_capabilities.rs @@ -8,9 +8,10 @@ use asap_cost::CostInputs; use asap_devtools::planning_stages::lower_sql_roots; use asap_logical_asap_optimization::{DeploymentCapabilities, SupportedSummary}; use asap_types::ir::flat::FlatDag; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{SketchAlgorithm, StatisticKind}; use asap_types::ir::{ASAPOp, Operator}; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use planner_layering_common::*; /// A deployment whose executor supports only `supported`: each family with @@ -199,8 +200,8 @@ type CandidateCosts = Vec<(String, f64)>; /// The per-second cost of every physical candidate whose tumbling-window chain both /// panels read is materialized at query time: shared within one evaluation -/// (`MatAtQuery`), and kept across evaluations -/// (`MatAtQueryKeptAcrossEvaluations`, which Stage 3 prices as such). +/// (`OneEvaluation`), and kept across evaluations +/// (query-time `AcrossEvaluations`, which Stage 3 prices as such). fn shared_chain_costs(run: &Run) -> (CandidateCosts, CandidateCosts) { let (mut within_one, mut kept) = (Vec::new(), Vec::new()); for p in &run.physical { @@ -214,12 +215,12 @@ fn shared_chain_costs(run: &Run) -> (CandidateCosts, CandidateCosts) { }; let entry = (p.id.clone(), cost.cost_per_second.expect("cost model 1")); let kept_detail = cost.per_node[&n.id].detail.contains("across evaluations"); - match n.materialization { - Materialization::MatAtQuery(_) => within_one.push(entry), - Materialization::MatAtQueryKeptAcrossEvaluations(_) if kept_detail => { + match (n.output_state.timing, n.lifetime) { + (_, Lifetime::OneEvaluation(_)) => within_one.push(entry), + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) if kept_detail => { kept.push(entry) } - Materialization::MatAtQueryKeptAcrossEvaluations(_) => { + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => { panic!("{}: a kept chain priced as not kept", p.id) } _ => {} diff --git a/crates/integration-tests/tests/materialization_e2e.rs b/crates/integration-tests/tests/materialization_e2e.rs index 1751d3e95..e782213e7 100644 --- a/crates/integration-tests/tests/materialization_e2e.rs +++ b/crates/integration-tests/tests/materialization_e2e.rs @@ -1,6 +1,6 @@ //! Materialization decides placement, not answers: the same selected DAG -//! timed with its states `NotMaterialized` (everything at query time) and -//! `MatAtIngestion` (materialized views refreshed at ingestion time) +//! timed with its states not kept (everything at query time) and +//! kept at ingestion time (materialized views refreshed at ingestion time) //! executes to the same result. use std::collections::{BTreeMap, HashMap}; @@ -24,11 +24,18 @@ use asap_types::ir::{ apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, OperatorNode, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; -use crate::physical_common; +/// Kept at ingestion time until a query reads it. +fn at_ingestion() -> Option { + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok() +} -const AT_INGESTION: Materialization = Materialization::MatAtIngestion(Medium::Memory); +use crate::physical_common; /// The logical DAG the planner pipeline selects for `query`, optionally with /// a PromQL series identity (per-entity state needs one). @@ -80,7 +87,7 @@ fn sketch_candidate(query: &str) -> Rc { fn placements() -> [MaterializationAssignment; 2] { [ MaterializationAssignment::default(), - MaterializationAssignment::with_default(AT_INGESTION), + MaterializationAssignment::with_default(at_ingestion()), ] } @@ -99,7 +106,10 @@ fn timed_dag(root: &Rc, assignment: &MaterializationAssignment) -> fn states(dag: &PhysicalASAPDAG) -> Vec { dag.nodes .iter() - .filter(|node| node.materialization == AT_INGESTION) + .filter(|node| { + node.output_state.timing == ExecutionTiming::IngestionTime + && node.lifetime == Lifetime::AcrossEvaluations(Medium::Memory) + }) .map(|node| node.id as u64) .collect() } @@ -198,8 +208,8 @@ fn values_1_to_100(schema: &SchemaRef, _metric: &str) -> Batch { Batch::try_new(schema.clone(), rows).unwrap() } -/// `MatAtIngestion` puts the quantile's state in a materialized view; -/// `NotMaterialized` has no view and reads the raw source at +/// Keeping it at ingestion time puts the quantile's state in a materialized view; +/// Not keeping it has no view and reads the raw source at /// query time; both answer alike. #[test] fn materialization_decides_precompute_contents() { @@ -220,8 +230,8 @@ fn materialization_decides_precompute_contents() { assert_eq!(answers[0], answers[1]); } -/// Mixed placement in one DAG: one summary `MatAtIngestion` (a materialized view) -/// and the other `NotMaterialized` (built from the raw source at query +/// Mixed placement in one DAG: one summary kept at ingestion time (a materialized view) +/// and the other not kept (built from the raw source at query /// time) answer like the all-query-time placement. #[test] fn mixed_placement_answers_like_query_time() { @@ -252,7 +262,7 @@ fn mixed_placement_answers_like_query_time() { "two explicitly selected KLL builds" ); let mut mixed = MaterializationAssignment::default(); - mixed.set(&sketches(&root)[0], AT_INGESTION); + mixed.set(&sketches(&root)[0], at_ingestion()); let mut answers = Vec::new(); for assignment in [MaterializationAssignment::default(), mixed] { let dag = timed_dag(&root, &assignment); diff --git a/crates/integration-tests/tests/materialized_views.rs b/crates/integration-tests/tests/materialized_views.rs index c6fad2f29..10aa58ca9 100644 --- a/crates/integration-tests/tests/materialized_views.rs +++ b/crates/integration-tests/tests/materialized_views.rs @@ -13,7 +13,7 @@ use asap_types::ir::operator::Source; use asap_types::ir::physical_export::{compile_physical_asap_workload, PhysicalASAPDAG}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ASAPOp, NonASAPOp, Operator}; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use asap_types::workload::PlanningWorkload; use serde_json::Value; @@ -54,10 +54,11 @@ fn stage3_raw_lookback_ms(dag: &PhysicalASAPDAG) -> Vec<(Source, Option)> { .iter() .filter(|node| { matches!( - (&node.payload, node.materialization), + (&node.payload, node.output_state.timing, node.lifetime), ( Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), - Materialization::MatAtQueryKeptAcrossEvaluations(_) + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(_) ) ) }) diff --git a/crates/integration-tests/tests/operator_design_examples.rs b/crates/integration-tests/tests/operator_design_examples.rs index 88b19291d..fac5da210 100644 --- a/crates/integration-tests/tests/operator_design_examples.rs +++ b/crates/integration-tests/tests/operator_design_examples.rs @@ -240,7 +240,7 @@ async fn sql_window_and_filtered_aggregate_types() { /// A real query batch replaces each SUM by its exact accumulator state, /// retains two result roots, and executes both selected plans. Pass 2 /// shares the identical state, and building the shared sub-DAG once per -/// evaluation for both queries (`MatAtQuery`, on the state or on its +/// evaluation for both queries (`OneEvaluation`, on the state or on its /// finalized sum above it) is the cheapest plan, so both roots read one /// state. No replacement dag is constructed by the test. #[tokio::test] @@ -309,12 +309,10 @@ async fn batch_planning_replaces_summary_operators() { panic!("one SUM state for both queries: {states:?}") }; assert!(output.operators().into_iter().any(|n| { - matches!( - n.materialization, - asap_types::physical::Materialization::MatAtQuery(_) - ) && OperatorNode::reachable(&n) - .iter() - .any(|m| Rc::ptr_eq(m, state)) + matches!(n.lifetime, asap_types::physical::Lifetime::OneEvaluation(_)) + && OperatorNode::reachable(&n) + .iter() + .any(|m| Rc::ptr_eq(m, state)) })); for (plan, expected) in output.plans.iter().zip([31.0, 60.0]) { let root = &plan.root; @@ -375,7 +373,7 @@ async fn batch_planning_replaces_summary_operators() { false }; assert!(workload_dag.nodes.iter().any(|n| matches!( - n.materialization, - asap_types::physical::Materialization::MatAtQuery(_) + n.lifetime, + asap_types::physical::Lifetime::OneEvaluation(_) ) && reaches_state(n.id))); } diff --git a/crates/integration-tests/tests/physical_common/mod.rs b/crates/integration-tests/tests/physical_common/mod.rs index e9f16cfa9..4a4b7e4c1 100644 --- a/crates/integration-tests/tests/physical_common/mod.rs +++ b/crates/integration-tests/tests/physical_common/mod.rs @@ -40,7 +40,7 @@ pub fn compile_physical_asap_dag( compile_with(root, &asap_types::ir::MaterializationAssignment::default()) } -/// As [`compile_physical_asap_dag`], with every sub-DAG `MatAtIngestion` +/// As [`compile_physical_asap_dag`], with every sub-DAG kept at ingestion time /// where the DAG allows it. #[allow(dead_code)] // Not every test binary sharing this module stores states at ingestion. pub fn compile_at_ingestion_physical_asap_dag( @@ -49,9 +49,13 @@ pub fn compile_at_ingestion_physical_asap_dag( compile_with( root, &asap_types::ir::MaterializationAssignment::with_default( - asap_types::physical::Materialization::MatAtIngestion( - asap_types::physical::Medium::Memory, - ), + asap_types::physical::PhysicalProperties::new( + asap_types::ir::properties::ExecutionTiming::IngestionTime, + asap_types::physical::Lifetime::AcrossEvaluations( + asap_types::physical::Medium::Memory, + ), + ) + .ok(), ), ) } diff --git a/crates/integration-tests/tests/planner_layering_common/mod.rs b/crates/integration-tests/tests/planner_layering_common/mod.rs index 47357ac32..a51dadabe 100644 --- a/crates/integration-tests/tests/planner_layering_common/mod.rs +++ b/crates/integration-tests/tests/planner_layering_common/mod.rs @@ -21,9 +21,10 @@ use asap_logical_asap_optimization::DeploymentCapabilities; use asap_plan_selection::reference_pricer::WholePlanSelection as Selection; use asap_types::ir::flat::{flatten, FlatDag, NodeId}; use asap_types::ir::physical_export::PhysicalASAPDAG; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm, SketchParams, SketchStatistic}; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, QueryRoot}; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use asap_types::physical::PhysicalWorkloadPlan; use asap_types::workload::{PlanningWorkload, QueryRecurrence, RepeatedDemand}; @@ -680,10 +681,7 @@ pub fn assert_one_unmaterialized_physical_candidate_per_logical(run: &Run) { assert_eq!(unmaterialized, !p.candidate.materializes_any(), "{}", p.id); if unmaterialized { for n in &p.dag().nodes { - assert_eq!( - materialization(p, n.id), - MaterializationOption::NotMaterialized - ); + assert_eq!(keeping(p, n.id), Keeping::NotKept); } } } @@ -771,16 +769,16 @@ pub fn assert_each_node_charged_per_consuming_query(run: &Run) { /// How many times each node is computed per evaluation of its consumers (#509; the /// rule of plan selection's private `computations`): 1 for a materialized -/// node; for a `NotMaterialized` one, the number of consumers that reach +/// node; for a not-kept one, the number of consumers that reach /// it. A consumer is a query (operator or scalar root) or a materialized /// node, whose walk starts at its inputs; a walk stops at materialized -/// nodes and counts each node once. The `MatAtIngestion` consumers of one +/// nodes and counts each node once. The consumers kept at ingestion time of one /// refresh window share one ingestion run and count once (#1151). pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { let materialized: BTreeSet<_> = dag .nodes .iter() - .filter(|n| n.materialization != Materialization::NotMaterialized) + .filter(|n| n.lifetime.is_kept()) .map(|n| n.id) .collect(); // Each walk's start and, for a consumer refreshed at ingestion, its @@ -795,14 +793,14 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { .map(|(_, expr)| (expr.operator_refs().into_iter().copied().collect(), None)), ) .chain(materialized.iter().map(|&id| { - let at_ingestion = matches!( - dag.nodes - .iter() - .find(|n| n.id == id) - .unwrap() - .materialization, - Materialization::MatAtIngestion(_) - ); + let at_ingestion = dag + .nodes + .iter() + .find(|n| n.id == id) + .unwrap() + .output_state + .timing + == ExecutionTiming::IngestionTime; let window = at_ingestion.then(|| dag.refresh_window(id)).flatten(); (dag.producers(id), window) })); @@ -838,32 +836,30 @@ pub fn evaluation_interval_ms(workload: &PlanningWorkload, query: usize) -> Opti } } -// ── Materialization ────────────────────────────────────────────────────── +// ── Kept outputs ───────────────────────────────────────────────────────── -/// A node's materialization option (#509 "Materialization"), without its -/// storage medium. +/// Whether a node's output is kept and at which timing, without how long +/// (`OneEvaluation` or `AcrossEvaluations`) or its storage medium. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum MaterializationOption { - /// Runs as data arrives; output stored before any query asks. - MatAtIngestion, +pub enum Keeping { + /// Runs as data arrives; output kept until a query reads it. + KeptAtIngestion, /// Runs when a query first needs it; output reused by the other - /// queries of the evaluation, or, as `MatAtQueryKeptAcrossEvaluations`, + /// queries of the evaluation, or, as query-time `AcrossEvaluations`, /// kept for later evaluations. - MatAtQuery, - /// Runs at query time for each execution; output discarded. - NotMaterialized, + KeptAtQueryTime, + /// Output discarded after its reader (lifetime `None`). + NotKept, } -/// The materialization option physical ASAP-aware optimization assigned to -/// `node` (#667). -pub fn materialization(p: &Physical, node: NodeId) -> MaterializationOption { +/// Whether physical ASAP-aware optimization keeps `node`'s output, and at +/// which timing (#667). +pub fn keeping(p: &Physical, node: NodeId) -> Keeping { let n = p.dag().nodes.iter().find(|n| n.id == node).expect("node"); - match n.materialization { - Materialization::MatAtIngestion(_) => MaterializationOption::MatAtIngestion, - Materialization::MatAtQuery(_) | Materialization::MatAtQueryKeptAcrossEvaluations(_) => { - MaterializationOption::MatAtQuery - } - Materialization::NotMaterialized => MaterializationOption::NotMaterialized, + match (n.output_state.timing, n.lifetime) { + (_, Lifetime::None) => Keeping::NotKept, + (ExecutionTiming::IngestionTime, _) => Keeping::KeptAtIngestion, + (ExecutionTiming::QueryTime, _) => Keeping::KeptAtQueryTime, } } diff --git a/crates/integration-tests/tests/planner_layering_example1.rs b/crates/integration-tests/tests/planner_layering_example1.rs index ca983c655..fa9a37a5d 100644 --- a/crates/integration-tests/tests/planner_layering_example1.rs +++ b/crates/integration-tests/tests/planner_layering_example1.rs @@ -15,7 +15,7 @@ use asap_planner::PlanningModels; use asap_types::ir::flat::NodeId; use asap_types::ir::schema::{FieldDataType, GroupingStrategy, HydraKind, SketchAlgorithm}; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, QueryRoot, ScalarExpr, SortKey}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium}; use planner_layering_common::*; // ── Example 1 workload ─────────────────────────────────────────────────── @@ -564,7 +564,7 @@ fn stage2_physical_asap_optimization_summary_topk_is_build_then_estimate() { /// chain is maintained or not independently: a logical candidate with `c` /// chains has `2^c` physical candidates. A shared input (the highest node /// both queries read: the scan, or the time range above it) is also built -/// once per evaluation (`MatAtQuery`), which adds one candidate: the one +/// once per evaluation (`OneEvaluation`), which adds one candidate: the one /// with every chain at query time, since a chain maintained at ingestion /// time leaves one query reading the input at query time. #[test] @@ -574,9 +574,9 @@ fn stage2_physical_asap_optimization_materializes_only_tumbling_windows_at_inges let mut shared_once = 0; for p in &run.physical { for n in &p.dag().nodes { - match materialization(p, n.id) { - MaterializationOption::NotMaterialized => {} - MaterializationOption::MatAtIngestion => { + match keeping(p, n.id) { + Keeping::NotKept => {} + Keeping::KeptAtIngestion => { let Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { family, .. }) = p.dag().payload(n.id) else { @@ -593,7 +593,7 @@ fn stage2_physical_asap_optimization_materializes_only_tumbling_windows_at_inges counter_maintained += 1; } } - MaterializationOption::MatAtQuery => { + Keeping::KeptAtQueryTime => { let (q1, q2) = roots(&p.query_roots); assert!( closure(p.dag(), q1).contains(&n.id) @@ -723,11 +723,11 @@ fn stage3_plan_selection_count_min_needs_the_counter_declaration() { ); } -/// A shared NotMaterialized input is charged once per consumer, and both +/// A shared not-kept input is charged once per consumer, and both /// queries read the same 1 m window, so the shared-input candidates cost /// what the independent one does; their totals differ from it only by /// floating-point rounding (the same charges summed in another grouping). -/// Built once per evaluation (`MatAtQuery`), the shared input is read once: +/// Built once per evaluation (`OneEvaluation`), the shared input is read once: /// the shared time range (the doc's "Raw with a shared input") is selected, /// at 4.38 instead of 7.01 per second. #[test] @@ -742,7 +742,7 @@ fn stage3_plan_selection_shared_input_ties_up_to_rounding_unless_built_once() { p.dag() .nodes .iter() - .any(|n| materialization(p, n.id) == MaterializationOption::MatAtQuery) + .any(|n| keeping(p, n.id) == Keeping::KeptAtQueryTime) }; let shared: Vec<_> = run .physical @@ -770,7 +770,7 @@ fn stage3_plan_selection_shared_input_ties_up_to_rounding_unless_built_once() { .dag() .nodes .iter() - .find(|n| materialization(selected, n.id) == MaterializationOption::MatAtQuery) + .find(|n| keeping(selected, n.id) == Keeping::KeptAtQueryTime) .unwrap(); assert_eq!( relational(&time_range.payload).as_deref(), @@ -817,7 +817,7 @@ fn stage3_plan_selection_selects_cheapest_valid() { } /// Every node of a valid candidate is charged once per consumer that reads -/// it: a shared `NotMaterialized` node is recomputed for each query, and a +/// it: a shared not-kept node is recomputed for each query, and a /// materialized one is computed once. #[test] fn stage3_plan_selection_charges_each_node_per_consuming_query() { @@ -825,7 +825,7 @@ fn stage3_plan_selection_charges_each_node_per_consuming_query() { } /// A hand-built candidate with a materialized node: Q1's plan read by two -/// queries, its `time_range` kept `MatAtQuery`. Plan selection charges the +/// queries, its `time_range` kept `OneEvaluation`. Plan selection charges the /// two accumulators (rate, sum) and their finalizations twice, once per query; the walks from /// both roots stop at the materialized `time_range`, which is computed once /// and reads the scan once. @@ -853,7 +853,7 @@ fn materialized_case() -> Run { .iter_mut() .find(|n| relational(&n.payload).as_deref() == Some("time_range")) .unwrap(); - time_range.materialization = Materialization::MatAtQuery(Medium::Memory); + time_range.lifetime = Lifetime::OneEvaluation(Medium::Memory); let selection = select_plan( std::slice::from_ref(&p.candidate), &[exact_every_10s(), exact_every_10s()], diff --git a/crates/integration-tests/tests/planner_layering_example4.rs b/crates/integration-tests/tests/planner_layering_example4.rs index a47c5fbfa..480d6ca98 100644 --- a/crates/integration-tests/tests/planner_layering_example4.rs +++ b/crates/integration-tests/tests/planner_layering_example4.rs @@ -66,7 +66,7 @@ fn options_of( run: &Run, form: Option, readers_count: usize, -) -> BTreeMap { +) -> BTreeMap { let logical = run .logical .iter() @@ -88,12 +88,12 @@ fn options_of( }) .map(|(id, ..)| id) .expect("the window summary survives physical ASAP-aware optimization"); - (materialization(p, id), (p.id.clone(), id)) + (keeping(p, id), (p.id.clone(), id)) }) .collect() } -fn eh_options(run: &Run) -> BTreeMap { +fn eh_options(run: &Run) -> BTreeMap { options_of(run, None, 5) } @@ -114,7 +114,7 @@ fn cost(run: &Run, id: &str) -> f64 { run.cost(id).unwrap_or_else(|| panic!("{id} is not priced")) } -use MaterializationOption::{MatAtIngestion, MatAtQuery, NotMaterialized}; +use Keeping::{KeptAtIngestion, KeptAtQueryTime, NotKept}; // ── Constraints over every candidate ───────────────────────────────────── @@ -168,12 +168,12 @@ fn assert_materialized_outputs_cover_their_consumers( // A shared scan or range built once per evaluation holds its // rows within that evaluation; plan selection reads it over the // longest window above it. - let shared_rows = materialization(p, n.id) == MatAtQuery + let shared_rows = keeping(p, n.id) == KeptAtQueryTime && matches!( relational(&n.payload).as_deref(), Some("scan" | "time_range" | "time_shift") ); - if materialization(p, n.id) == NotMaterialized || shared_rows { + if keeping(p, n.id) == NotKept || shared_rows { continue; } let need = readers(p.dag(), &p.query_roots, n.id) @@ -215,30 +215,30 @@ fn stage2_physical_asap_optimization_monthly_materialized_output_covers_its_cons /// The shared EH candidate yields A1 (query time, kept), A2 (ingestion time) and A3 (not materialized). #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_shared_eh_has_three_materialization_options() { let found: BTreeSet<_> = eh_options(&run_promql(&once())).into_keys().collect(); assert_eq!( found, - BTreeSet::from([MatAtIngestion, MatAtQuery, NotMaterialized]) + BTreeSet::from([KeptAtIngestion, KeptAtQueryTime, NotKept]) ); } /// With data at rest, A2 is not generated; A1 and A3 remain. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option() { let found: BTreeSet<_> = eh_options(&run_promql(&at_rest())).into_keys().collect(); - assert_eq!(found, BTreeSet::from([MatAtQuery, NotMaterialized])); + assert_eq!(found, BTreeSet::from([KeptAtQueryTime, NotKept])); } /// A materialized shared EH is one build node read by all five queries, charged once. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers() { let run = run_promql(&once()); for (m, (id, build)) in eh_options(&run) { - if m == NotMaterialized { + if m == NotKept { continue; } let p = run.physical(&id); @@ -261,14 +261,14 @@ fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_con } /// A3 rebuilds the EH for each of the five queries (plan selection charges a -/// `NotMaterialized` node once per consuming query), so it costs more than A1, +/// not-kept node once per consuming query), so it costs more than A1, /// which builds it once. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() { let run = run_promql(&once()); let options = eh_options(&run); - let (a1, a3) = (&options[&MatAtQuery].0, &options[&NotMaterialized].0); + let (a1, a3) = (&options[&KeptAtQueryTime].0, &options[&NotKept].0); assert!( cost(&run, a3) > cost(&run, a1), "A3 {} vs A1 {}", @@ -279,11 +279,11 @@ fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() /// As given (run once, ad hoc), A1 is the cheapest of the three: A2 maintains years of history for one batch. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh() { let run = run_promql(&once()); let options = eh_options(&run); - let a1 = cost(&run, &options[&MatAtQuery].0); + let a1 = cost(&run, &options[&KeptAtQueryTime].0); for (m, (id, _)) in &options { assert!(a1 <= cost(&run, id), "A1 {a1} vs {m:?} {}", cost(&run, id)); } @@ -291,12 +291,12 @@ fn stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh() { /// Repeated monthly and predictable, A2's maintenance is shared by many batches, so A2 gains on A1. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materialization (MatAtQuery within one batch) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance() { let ratio = |workload: PlanningWorkload| { let run = run_promql(&workload); let options = eh_options(&run); - cost(&run, &options[&MatAtIngestion].0) / cost(&run, &options[&MatAtQuery].0) + cost(&run, &options[&KeptAtIngestion].0) / cost(&run, &options[&KeptAtQueryTime].0) }; let (once, monthly) = (ratio(once()), ratio(monthly())); assert!(monthly < once, "A2/A1: monthly {monthly} vs once {once}"); @@ -324,7 +324,7 @@ fn stage2_physical_asap_optimization_b_tumbling_kll_has_three_materialization_op let found: BTreeSet<_> = options_of(&run, tumbling(), 1).into_keys().collect(); assert_eq!( found, - BTreeSet::from([MatAtIngestion, MatAtQuery, NotMaterialized]) + BTreeSet::from([KeptAtIngestion, KeptAtQueryTime, NotKept]) ); } @@ -336,7 +336,7 @@ fn stage2_physical_asap_optimization_b_b1_builds_at_ingestion_and_merges_at_quer &CostInputs::default(), &DeploymentCapabilities::default(), ); - let (id, build) = options_of(&run, tumbling(), 1)[&MatAtIngestion].clone(); + let (id, build) = options_of(&run, tumbling(), 1)[&KeptAtIngestion].clone(); let p = run.physical(&id); assert!(runs_at_ingestion(p, build)); let estimates = estimates_of(p.dag(), build); @@ -370,7 +370,7 @@ fn stage2_physical_asap_optimization_b_tumbling_kll_has_b1_and_b2() { let options = options_of(&run, tumbling(), 1); assert_eq!( options.keys().copied().collect::>(), - BTreeSet::from([MatAtIngestion, NotMaterialized]) + BTreeSet::from([KeptAtIngestion, NotKept]) ); for (id, _) in options.values() { assert!(run.cost(id).is_some(), "{id} is priced"); @@ -391,7 +391,7 @@ fn stage2_physical_asap_optimization_b_b3_keeps_query_time_windows() { &keeping_query_time_results(), ); let options = options_of(&run, tumbling(), 1); - let (id, build) = options[&MatAtQuery].clone(); + let (id, build) = options[&KeptAtQueryTime].clone(); let p = run.physical(&id); assert!( p.dag().nodes.iter().all(|n| !runs_at_ingestion(p, n.id)), @@ -399,7 +399,7 @@ fn stage2_physical_asap_optimization_b_b3_keeps_query_time_windows() { ); assert_eq!(retention_ms(p, build), Some(PATTERN_B_WINDOW_MS)); let disk = |id: &str| run.selection.costs[id].usage.disk_bytes; - assert_eq!(disk(&id) * 5, disk(&options[&NotMaterialized].0)); + assert_eq!(disk(&id) * 5, disk(&options[&NotKept].0)); } /// The sliding-window KLL is kept from ingestion time or from query time; not materializing it is the no-window plan. @@ -417,7 +417,7 @@ fn stage2_physical_asap_optimization_b_sliding_kll_has_two_materialization_optio ) .into_keys() .collect(); - assert_eq!(found, BTreeSet::from([MatAtIngestion, MatAtQuery])); + assert_eq!(found, BTreeSet::from([KeptAtIngestion, KeptAtQueryTime])); } // ── Cost models (#683, #660) ───────────────────────────────────────────── @@ -452,10 +452,10 @@ fn pattern_b_candidates(run: &Run) -> PatternBCandidates { .expect("an exact candidate") .id .clone(), - whole_window_kll: options_of(run, Some(WindowForm::None), 1)[&NotMaterialized] + whole_window_kll: options_of(run, Some(WindowForm::None), 1)[&NotKept] .0 .clone(), - b1: tumbling_windows[&MatAtIngestion].0.clone(), + b1: tumbling_windows[&KeptAtIngestion].0.clone(), } } diff --git a/crates/integration-tests/tests/production_rollup_workloads.rs b/crates/integration-tests/tests/production_rollup_workloads.rs index c44f7724a..1c41e2abe 100644 --- a/crates/integration-tests/tests/production_rollup_workloads.rs +++ b/crates/integration-tests/tests/production_rollup_workloads.rs @@ -262,7 +262,7 @@ fn independent_kll_cost( entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(asap_types::physical::Materialization::NotMaterialized), + &mut |_, _, _| Some(None), ) .unwrap() .unwrap(); diff --git a/crates/integration-tests/tests/range_evaluation.rs b/crates/integration-tests/tests/range_evaluation.rs index 2f97eeb72..1d3ccc091 100644 --- a/crates/integration-tests/tests/range_evaluation.rs +++ b/crates/integration-tests/tests/range_evaluation.rs @@ -10,8 +10,9 @@ use crate::planner_layering_common; use asap_logical_asap_optimization::DeploymentCapabilities; use asap_plan_selection::RejectionCause; use asap_types::ir::physical_export::PhysicalASAPOperatorPayload; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::ASAPOp; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium}; use asap_types::workload::{ DataArrival, DataWorkload, DurationMs, PlanningWorkload, Predictability, Query, QueryLanguage, QueryRequirements, QueryWorkload, RangeEvaluation, RepeatedDemand, RepeatingEntry, @@ -155,8 +156,9 @@ fn close(actual: f64, expected: f64) -> bool { (actual - expected).abs() <= 1e-6 * expected.abs().max(1.0) } -/// Each physical candidate's tumbling-window chains: (tumbling-window width, materialization). -fn tumbling_window_chains(run: &Run) -> Vec<(String, u64, Materialization)> { +/// Each physical candidate's tumbling-window chains: (tumbling-window width, +/// (timing, lifetime)). +fn tumbling_window_chains(run: &Run) -> Vec<(String, u64, (ExecutionTiming, Lifetime))> { run.physical .iter() .flat_map(|p| { @@ -164,15 +166,20 @@ fn tumbling_window_chains(run: &Run) -> Vec<(String, u64, Materialization)> { PhysicalASAPOperatorPayload::ASAP(ASAPOp::SummaryTumblingWindowChain { tumbling_window_width_ms, .. - }) => Some((p.id.clone(), *tumbling_window_width_ms, n.materialization)), + }) => Some(( + p.id.clone(), + *tumbling_window_width_ms, + (n.output_state.timing, n.lifetime), + )), _ => None, }) }) .collect() } -/// The candidate whose single tumbling-window chain is materialized as `wanted`. -fn with_chain(run: &Run, wanted: Materialization) -> String { +/// The candidate whose single tumbling-window chain runs at and is kept as +/// `wanted`. +fn with_chain(run: &Run, wanted: (ExecutionTiming, Lifetime)) -> String { tumbling_window_chains(run) .into_iter() .find(|(_, _, m)| *m == wanted) @@ -272,7 +279,10 @@ fn stage3_plan_selection_reports_the_retention_of_kept_tumbling_windows() { ); let kept = with_chain( &range, - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), + ( + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ), ); assert_eq!(range.selection.selected, kept); let retention: Vec = range @@ -349,9 +359,18 @@ fn stage3_plan_selection_prefers_kept_tumbling_windows_once_the_range_is_declare ); let kept = with_chain( &range, - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), + ( + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ), + ); + let ingestion = with_chain( + &range, + ( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ), ); - let ingestion = with_chain(&range, Materialization::MatAtIngestion(Medium::Memory)); for (run, id, expected) in [ (&none, "P1", 20.828_117), (&none, kept.as_str(), 32.262_967), diff --git a/crates/integration-tests/tests/reuse_rules.rs b/crates/integration-tests/tests/reuse_rules.rs index 2c8d5a4ad..59865da82 100644 --- a/crates/integration-tests/tests/reuse_rules.rs +++ b/crates/integration-tests/tests/reuse_rules.rs @@ -23,7 +23,7 @@ use asap_types::ir::{ apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, OperatorNode, QueryRoot, }; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use asap_types::stages::{root_groups, MemoGroupId}; use asap_types::stages::{Memo, OriginOfCandidateForMemoGroup}; use asap_types::workload::{ @@ -191,7 +191,7 @@ fn candidates_of<'a>( /// group on its first candidate (`group`), and `variant{i}` per entry of /// `variants`, a group's candidate index each. Returns the selected plan's /// name, its roots, whether it builds some computation once per evaluation -/// for all its readers (`MatAtQuery`), and the selection's lowest prices of +/// for all its readers (`OneEvaluation`), and the selection's lowest prices of /// `group` and of every variant. fn select( memo: &Memo, @@ -225,9 +225,9 @@ fn select( .expect("the selected plan"); let name = selected.from_logical.clone(); let built_once = selected - .materialization + .lifetime .values() - .any(|m| matches!(m, Materialization::MatAtQuery(_))); + .any(|lifetime| matches!(lifetime, Lifetime::OneEvaluation(_))); let roots = plans .iter() .find(|(n, _)| *n == name) @@ -304,7 +304,7 @@ fn shared_kinds(roots: &[Rc]) -> BTreeSet { /// queries, among the queries' own roots and the plans reading `origin` /// candidates (the `i`-th of each group that has some, together). Stage 2 /// offers each computation two queries read built once per evaluation -/// (`MatAtQuery`); the reuse plan is selected and is cheaper than without it. +/// (`OneEvaluation`); the reuse plan is selected and is cheaper than without it. fn selected_reuse(queries: &[&str], origin: OriginOfCandidateForMemoGroup) -> BTreeSet { let memo = memo(&exact_queries(queries), repeating()); let mut by_group: BTreeMap> = BTreeMap::new(); diff --git a/crates/integration-tests/tests/rollup_controlled.rs b/crates/integration-tests/tests/rollup_controlled.rs index d646ded6b..2b3bc1ad4 100644 --- a/crates/integration-tests/tests/rollup_controlled.rs +++ b/crates/integration-tests/tests/rollup_controlled.rs @@ -12,7 +12,7 @@ use asap_types::{ schema::{DataType, Field, Schema, SketchAlgorithm}, ASAPOp, OperatorNode, QueryRoot, }, - physical::{Materialization, Medium}, + physical::PhysicalProperties, workload::PlanningWorkload, }; use std::{collections::HashSet, rc::Rc}; @@ -117,11 +117,22 @@ fn controlled_distinct_rollup_prices_the_original_workload() { data, models.deployment_capabilities.query_time_results_retained, &mut |node, _, options| { - let mat = Materialization::MatAtQuery(Medium::Memory); - Some(if builds.contains(&node) && options.contains(&mat) { - mat - } else { - Materialization::NotMaterialized + // Kept for one evaluation where offered, as two + // queries reading one build allow. + let shared: Option> = options + .iter() + .find(|kept| { + kept.is_some_and(|p| { + matches!( + p.lifetime(), + asap_types::physical::Lifetime::OneEvaluation(_) + ) + }) + }) + .copied(); + Some(match shared { + Some(kept) if builds.contains(&node) => kept, + _ => None, }) }, ) diff --git a/crates/integration-tests/tests/runtime_handoff.rs b/crates/integration-tests/tests/runtime_handoff.rs index cadfe8788..4542413bc 100644 --- a/crates/integration-tests/tests/runtime_handoff.rs +++ b/crates/integration-tests/tests/runtime_handoff.rs @@ -16,7 +16,6 @@ use asap_types::ir::physical_export::{ }; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ASAPOp, Operator}; -use asap_types::physical::Materialization; use asap_types::workload::PlanningWorkload; /// #509 Example 4b: one repeating `quantile_over_time` over a 60-minute @@ -63,10 +62,7 @@ async fn plan(workload: &PlanningWorkload, capabilities: &DeploymentCapabilities } fn materialized_count(dag: &PhysicalASAPDAG) -> usize { - dag.nodes - .iter() - .filter(|n| n.materialization != Materialization::NotMaterialized) - .count() + dag.nodes.iter().filter(|n| n.lifetime.is_kept()).count() } /// Without raw data Stage 3 selects ingestion-time tumbling windows; the facade's diff --git a/crates/integration-tests/tests/sharing_issue_regressions.rs b/crates/integration-tests/tests/sharing_issue_regressions.rs index 04555299e..5963efbd3 100644 --- a/crates/integration-tests/tests/sharing_issue_regressions.rs +++ b/crates/integration-tests/tests/sharing_issue_regressions.rs @@ -58,8 +58,8 @@ fn cost(w: &FuzzWorkload) -> f64 { } /// #923: deriving the coarse sum costs only a sum over the 150 fine groups. -/// Stage 2 offers that plan; Stage 3 keeps a `MatAtQuery` build whose -/// `NotMaterialized` sibling would avoid a second scan (#1142). +/// Stage 2 offers that plan; Stage 3 keeps a `OneEvaluation` build whose +/// not-kept sibling would avoid a second scan (#1142). #[test] #[ignore = "Stage 3 misses the cheaper plan Stage 2 offers (#1142)"] fn exact_coarse_sum_reuses_fine_sum() { diff --git a/crates/integration-tests/tests/tumbling_window_merge.rs b/crates/integration-tests/tests/tumbling_window_merge.rs index 7f5c7cff2..14ba14564 100644 --- a/crates/integration-tests/tests/tumbling_window_merge.rs +++ b/crates/integration-tests/tests/tumbling_window_merge.rs @@ -22,13 +22,14 @@ use asap_logical_asap_optimization::test_support::{ use asap_types::ir::operator::operator_properties::TimeShift; use asap_types::ir::operator::tumbling_window_chain::expand_tumbling_window_chains; use asap_types::ir::physical_export::PhysicalASAPDAG; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::properties::{AccuracyMetric, AccuracyTarget}; use asap_types::ir::schema::Schema; use asap_types::ir::{ apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::test_support::compile_physical_asap_dag_with_node_ids; const EVALUATION_MS: i64 = 300_000; @@ -269,7 +270,7 @@ fn execute(root: &Rc, samples: &[RawDataSample]) -> Vec run(&plan, raw_store(&exported.dag, samples), query_scope()) } -/// Build the tumbling windows in ingestion runs (stored `MatAtIngestion`, each with its +/// Build the tumbling windows in ingestion runs (kept at ingestion time, each with its /// own build timestamp), then merge them in the query run (Pattern B1). fn execute_retained( root: &Rc, @@ -280,15 +281,19 @@ fn execute_retained( for tumbling_window in tumbling_windows { assignment.set( tumbling_window, - Materialization::MatAtIngestion(Medium::Memory), + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), ); } execute_retained_as(root, &assignment, samples) } /// The planner's tumbling-window chain maintained at ingestion time, as Stage 2's B1 -/// option assigns it (`MatAtIngestion` on the chain), then expanded: each -/// tumbling window carries the chain's timing and materialization, so the tumbling windows are +/// option assigns it (kept at ingestion time on the chain), then expanded: each +/// tumbling window carries the chain's timing and lifetime, so the tumbling windows are /// built in ingestion runs and merged in the query run. fn execute_maintained_chain( planned: &Rc, @@ -299,7 +304,14 @@ fn execute_maintained_chain( .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. }))) .expect("a tumbling-window chain"); let mut assignment = MaterializationAssignment::default(); - assignment.set(&chain, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + &chain, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); let timed = apply_materialization_timings(planned, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -309,9 +321,10 @@ fn execute_maintained_chain( .filter(|n| matches!(n.asap(), Some(ASAPOp::SummaryAgg { .. }))) { assert_eq!( - tumbling_window.materialization, - Materialization::MatAtIngestion(Medium::Memory) + tumbling_window.lifetime, + Lifetime::AcrossEvaluations(Medium::Memory) ); + assert_eq!(tumbling_window.timing, Some(ExecutionTiming::IngestionTime)); } execute_retained_as(&expanded, &MaterializationAssignment::default(), samples) } diff --git a/crates/logical-asap-optimization/src/deployment_capabilities.rs b/crates/logical-asap-optimization/src/deployment_capabilities.rs index f449513b6..5caa09a78 100644 --- a/crates/logical-asap-optimization/src/deployment_capabilities.rs +++ b/crates/logical-asap-optimization/src/deployment_capabilities.rs @@ -20,10 +20,10 @@ //! contradiction, refused as bad input ([`DeploymentCapabilities::validate`]); //! * whether query-time results are retained across evaluations. If they //! are, Stage 2 also offers a tumbling-window chain whose readers evaluate -//! together at its tumbling-window width as `MatAtQueryKeptAcrossEvaluations`: each +//! together at its tumbling-window width as query-time `AcrossEvaluations`: each //! evaluation builds one new tumbling window and keeps the others for the next ones, //! covering the readers' longest look-back. A chain two or more queries -//! read keeps its `MatAtQuery` option too (shared within one evaluation), +//! read keeps its `OneEvaluation` option too (shared within one evaluation), //! and Stage 3 picks the cheaper. If they are not, a query-time result is //! reused only within one evaluation. //! @@ -53,7 +53,7 @@ pub struct DeploymentCapabilities { /// Whether raw data samples are kept for query-time scans; default `true`. pub raw_data_retained: bool, /// Whether a query-time result may be kept across evaluations - /// (`MatAtQueryKeptAcrossEvaluations`); default `false`. + /// (query-time `AcrossEvaluations`); default `false`. pub query_time_results_retained: bool, } diff --git a/crates/logical-asap-optimization/src/pass1/memo_population.rs b/crates/logical-asap-optimization/src/pass1/memo_population.rs index b3b411f1a..95b8b15f5 100644 --- a/crates/logical-asap-optimization/src/pass1/memo_population.rs +++ b/crates/logical-asap-optimization/src/pass1/memo_population.rs @@ -437,7 +437,7 @@ fn builds_a_sketch(node: &Rc) -> bool { } /// Interned structural identities: the operator over its children's identities, -/// without the schema, guarantee, timing and materialization composition +/// without the schema, guarantee, timing and lifetime composition /// derives. Memoized per node (the cache keeps each node alive, so its /// address is not reused). #[derive(Default)] diff --git a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs index ea2b891ca..1e4aa4a82 100644 --- a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs +++ b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs @@ -120,7 +120,7 @@ use asap_types::ir::{ ASAPOp, BinaryOperator, ExprSemantics, NonASAPOp, Operator, OperatorNode, OperatorResultKind, Predicate, ProjectItem, QueryRoot, ScalarExpr, SchemaDerivationError, }; -use asap_types::physical::Materialization; +use asap_types::physical::Lifetime; use thiserror::Error; use asap_accuracy::composition::parse_raw_data_samples_sign_statistic; @@ -667,7 +667,7 @@ fn absorbed_targets(targets: &[ComputationTarget]) -> impl Iterator bool { && left.schema == right.schema && left.result_kind == right.result_kind && left.timing == right.timing - && left.materialization == right.materialization + && left.lifetime == right.lifetime && left .children() .iter() diff --git a/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs b/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs index 5d45eac0d..dff62027e 100644 --- a/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs +++ b/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs @@ -54,7 +54,7 @@ fn with_child_nodes( OperatorNode::with_schema(operator, resized.schema.clone()) .with_guarantee(resized.guarantee.clone()) .with_timing(resized.timing) - .with_materialization(resized.materialization), + .with_lifetime(resized.lifetime), ), }; done.insert(Rc::as_ptr(resized), Rc::clone(&out)); @@ -134,10 +134,7 @@ impl SharedProducer for SummaryStates { }; // Configuration expansion precedes Stage 2. The rewrite helpers // create unassigned state; preserve any already assigned build. - if build.timing.is_some() - || build.materialization - != asap_types::physical::Materialization::NotMaterialized - { + if build.timing.is_some() || build.lifetime.is_kept() { continue; } let family = match build.asap() { @@ -488,7 +485,7 @@ fn compatible(left: &StateNeed, right: &StateNeed) -> bool { schema, reader.build.result_kind, reader.build.timing, - reader.build.materialization, + reader.build.lifetime, )) .ok() }; diff --git a/crates/logical-asap-optimization/src/pass2/memo/state_groups.rs b/crates/logical-asap-optimization/src/pass2/memo/state_groups.rs index e0c5bf94c..5c8b70270 100644 --- a/crates/logical-asap-optimization/src/pass2/memo/state_groups.rs +++ b/crates/logical-asap-optimization/src/pass2/memo/state_groups.rs @@ -384,7 +384,7 @@ fn local_fingerprint(node: &OperatorNode) -> Option { node.result_kind, &node.guarantee, node.timing, - node.materialization, + node.lifetime, )) .ok() } @@ -450,7 +450,7 @@ fn same_local_fields(left: &OperatorNode, right: &OperatorNode) -> bool { node.schema.clone(), node.guarantee.clone(), node.timing, - node.materialization, + node.lifetime, ) }; let left = signature(left); diff --git a/crates/logical-asap-optimization/src/pass2/memo/window_candidates.rs b/crates/logical-asap-optimization/src/pass2/memo/window_candidates.rs index 468de54d5..57ae7f531 100644 --- a/crates/logical-asap-optimization/src/pass2/memo/window_candidates.rs +++ b/crates/logical-asap-optimization/src/pass2/memo/window_candidates.rs @@ -110,7 +110,7 @@ fn local_tumbling_window_candidates( && original.schema == rewritten.schema && original.result_kind == rewritten.result_kind && original.timing == rewritten.timing - && original.materialization == rewritten.materialization + && original.lifetime == rewritten.lifetime }); if let Some(original) = matches.next() { if matches.next().is_none() { @@ -158,7 +158,7 @@ fn restore_scan_boundaries( OperatorNode::with_schema(operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } else { Rc::clone(node) diff --git a/crates/logical-asap-optimization/src/stage0/cse.rs b/crates/logical-asap-optimization/src/stage0/cse.rs index 6f209a4e6..5aa44c31a 100644 --- a/crates/logical-asap-optimization/src/stage0/cse.rs +++ b/crates/logical-asap-optimization/src/stage0/cse.rs @@ -117,7 +117,7 @@ pub(crate) fn structural_hash(node: &OperatorNode, cache: &mut NodeToStructuralH &node.schema, &node.guarantee, node.timing, - node.materialization, + node.lifetime, ); serde_json::to_string(&own) .unwrap_or_default() @@ -178,7 +178,7 @@ fn same_node( && left.result_kind == right.result_kind && left.schema == right.schema && left.timing == right.timing - && left.materialization == right.materialization + && left.lifetime == right.lifetime && same_value(&left.guarantee, &right.guarantee) && same_value(&own_fields(left), &own_fields(right)) } @@ -260,7 +260,7 @@ fn intern_bottom_up( let rebuilt = OperatorNode::with_schema(operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization); + .with_lifetime(node.lifetime); let interned = table.intern(rebuilt); visited.insert(Rc::as_ptr(node), (Rc::clone(node), Rc::clone(&interned))); interned diff --git a/crates/logical-asap-optimization/src/test_support.rs b/crates/logical-asap-optimization/src/test_support.rs index 988cb4210..1e013975b 100644 --- a/crates/logical-asap-optimization/src/test_support.rs +++ b/crates/logical-asap-optimization/src/test_support.rs @@ -111,9 +111,10 @@ use asap_types::ir::operator::operator_properties::{GroupKeys, Reduction, Source use asap_types::ir::properties::timing::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, }; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{ColumnId, DataType, Field, Schema}; use asap_types::ir::{NonASAPOp, Predicate, ScalarExpr, TimeRangeKind}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; /// A `TimeSeries("m")` scan over `[ts(0), value(1), labels...]`, time index 0, /// no unique key. @@ -220,7 +221,7 @@ pub fn time_range(range: Duration, child: Rc) -> Rc .unwrap() } -/// `root` timed under the default (every sub-DAG `NotMaterialized`) +/// `root` timed under the default (every sub-DAG not kept) /// assignment — the shape export and the post-ASAP validators consume. pub fn timed(root: &Rc) -> Rc { apply_materialization_timings( @@ -231,11 +232,17 @@ pub fn timed(root: &Rc) -> Rc { .expect("default materialization timings apply") } -/// `root` timed with every sub-DAG `MatAtIngestion` where the DAG allows it. +/// `root` timed with every sub-DAG kept at ingestion time where the DAG allows it. pub fn at_ingestion(root: &Rc) -> Rc { apply_materialization_timings( root, - &MaterializationAssignment::with_default(Materialization::MatAtIngestion(Medium::Memory)), + &MaterializationAssignment::with_default( + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ), &mut NodeToTimedNodeCache::new(), ) .expect("at-ingestion materialization timings apply") diff --git a/crates/physical-asap-optimization/src/catalog/configurations.rs b/crates/physical-asap-optimization/src/catalog/configurations.rs index c5b8ade0a..6a1f9ae55 100644 --- a/crates/physical-asap-optimization/src/catalog/configurations.rs +++ b/crates/physical-asap-optimization/src/catalog/configurations.rs @@ -4,16 +4,20 @@ //! conjunction of individual-reader restrictions and pairwise interval/phase //! compatibility; selected-reader constraints encode those conditions. Complete //! Stage 2 validation still checks operator legality and upstream timing. -//! Potential shared non-summary nodes also receive query materialization; Stage 2 +//! Potential shared non-summary nodes also receive query-time `OneEvaluation`; Stage 2 //! checks highest-shared eligibility on the selected graph, not all possible consumers. use asap_types::stages::{ProducerCandidates, ProducerSetInterner}; use std::collections::HashMap; -use crate::summary_materialization_eligibility; +use crate::{ + kept_across_evaluations_at_ingestion, kept_across_evaluations_at_query_time, + kept_for_one_evaluation, physical_properties as properties, + summary_materialization_eligibility, +}; use asap_types::ir::operator::{agg_has_exact_per_entity_kernel, Reduction}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, PhysicalProperties}; use asap_types::workload::{DataWorkload, QueryWorkloadEntry}; use super::inventory::CandidateInventory; @@ -25,19 +29,19 @@ use asap_types::stages::{ }; /// [`PhysicalCandidate::may_keep_across_evaluations_per_sole_reader_query`] for `node` configured -/// with `materialization`: for each query in `entries`, whether +/// with `properties`: for each query in `entries`, whether /// `summary_materialization_eligibility` with that query as the only reader /// allows keeping it across evaluations. Empty unless `node` is a tumbling-window chain, -/// `materialization` is `MatAtQueryKeptAcrossEvaluations(Memory)` and the +/// `properties` is query time kept `AcrossEvaluations(Memory)` and the /// deployment keeps query-time results. pub fn may_keep_across_evaluations_per_sole_reader_query( node: &OperatorNode, - materialization: Materialization, + properties: PhysicalProperties, entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, ) -> Vec { - if materialization != Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory) + if properties != kept_across_evaluations_at_query_time() || !matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) || !query_time_results_retained { @@ -61,11 +65,11 @@ pub fn may_keep_across_evaluations_per_sole_reader_query( pub enum ConfigurationError { #[error("invalid source candidate inventory: {0}")] InvalidInventory(String), - #[error("candidate {candidate} already has timing or materialization assigned")] + #[error("candidate {candidate} already has timing or lifetime assigned")] AssignedExecution { candidate: usize }, } -/// Each operator node of `source` with every timing and materialization +/// Each operator node of `source` with every timing and lifetime /// Stage 2 allows, one candidate each. `query_roots` are the memo's; their /// group references are `source`'s output references. pub fn enumerate_candidate_configurations( @@ -122,7 +126,7 @@ pub fn enumerate_candidate_configurations( let mut source_configurations = vec![Vec::new(); source_count]; for source_id in 0..source_count { let node = &source.operator_nodes_of_candidates_for_memo_groups[source_id].physical_node; - if node.timing.is_some() || node.materialization != Materialization::NotMaterialized { + if node.timing.is_some() || node.lifetime.is_kept() { return Err(ConfigurationError::AssignedExecution { candidate: source_id, }); @@ -144,71 +148,55 @@ pub fn enumerate_candidate_configurations( .enumerate() .filter_map(|(query, reached)| reached.then_some(query)) .collect::>(); - let mut modes = vec![(Materialization::NotMaterialized, ExecutionTiming::QueryTime)]; + let mut alternatives = vec![properties(ExecutionTiming::QueryTime, Lifetime::None)]; if summary { - modes.push(( - Materialization::MatAtQuery(Medium::Memory), - ExecutionTiming::QueryTime, - )); + alternatives.push(kept_for_one_evaluation()); if queries.iter().any(|&query| { - summary_mode_allowed( + summary_properties_allowed( node, &[query], - Materialization::MatAtIngestion(Medium::Memory), + kept_across_evaluations_at_ingestion(), entries, data, query_time_results_retained, ) }) { - modes.push(( - Materialization::MatAtIngestion(Medium::Memory), - ExecutionTiming::IngestionTime, - )); + alternatives.push(kept_across_evaluations_at_ingestion()); } if matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) && queries.iter().any(|&query| { - summary_mode_allowed( + summary_properties_allowed( node, &[query], - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), + kept_across_evaluations_at_query_time(), entries, data, query_time_results_retained, ) }) { - modes.push(( - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), - ExecutionTiming::QueryTime, - )); + alternatives.push(kept_across_evaluations_at_query_time()); } } else if !forced_query { - modes.push(( - Materialization::NotMaterialized, - ExecutionTiming::IngestionTime, - )); + alternatives.push(properties(ExecutionTiming::IngestionTime, Lifetime::None)); } // Potential reach only generates the choice. Selected-reader cardinality // and Stage 2's highest-shared rule determine actual eligibility. if !summary && queries.len() >= 2 { - modes.push(( - Materialization::MatAtQuery(Medium::Memory), - ExecutionTiming::QueryTime, - )); + alternatives.push(kept_for_one_evaluation()); } // Configurations the deployment cannot run are not generated; each is // recorded as pruned. let group = source.operator_nodes_of_candidates_for_memo_groups[source_id].group(); - let mut prune_modes = |reason, applies: &dyn Fn(ExecutionTiming) -> bool| { - modes.retain(|&(materialization, timing)| { - let pruned = applies(timing); + let mut prune_alternatives = |reason, applies: &dyn Fn(ExecutionTiming) -> bool| { + alternatives.retain(|&properties| { + let pruned = applies(properties.timing()); if pruned { pruned_candidates.push(PrunedCandidate { group, candidate: PhysicalCandidateKey { operator_node: OperatorNodeOfCandidateForMemoGroupId(source_id), - timing, - materialization, + properties, }, reason, }); @@ -217,35 +205,35 @@ pub fn enumerate_candidate_configurations( }); }; if !per_entity_aggregate_executable(node) { - prune_modes(PruneReason::PerEntityAggregateNotExecutable, &|_| true); + prune_alternatives(PruneReason::PerEntityAggregateNotExecutable, &|_| true); } // Without raw data retained, only ingestion-time work reads raw rows. if !raw_data_retained && matches!(node.operator, Operator::NonASAP(NonASAPOp::Scan { .. })) { - prune_modes(PruneReason::RawDataNotRetained, &|timing| { + prune_alternatives(PruneReason::RawDataNotRetained, &|timing| { timing != ExecutionTiming::IngestionTime }); } - for (materialization, timing) in modes { + for properties in alternatives { + let timing = properties.timing(); let id = PhysicalCandidateId(candidates.len()); source_configurations[source_id].push(id); candidates.push(PhysicalCandidate { operator_node: OperatorNodeOfCandidateForMemoGroupId(source_id), - timing, - materialization, + properties, producer_candidates_per_input: Vec::new(), may_produce_query_output: may_produce_query_output[source_id] && timing == ExecutionTiming::QueryTime, may_keep_across_evaluations_per_sole_reader_query: may_keep_across_evaluations_per_sole_reader_query( node, - materialization, + properties, entries, data, query_time_results_retained, ), }); - if materialization == Materialization::MatAtQuery(Medium::Memory) { + if properties == kept_for_one_evaluation() { if !summary { reader_constraints.push(ReaderConstraint::HighestSharedQueryMaterialization { candidate: id, @@ -263,10 +251,10 @@ pub fn enumerate_candidate_configurations( .iter() .copied() .filter(|&query| { - summary_mode_allowed( + summary_properties_allowed( node, &[query], - materialization, + properties, entries, data, query_time_results_retained, @@ -286,10 +274,10 @@ pub fn enumerate_candidate_configurations( // approximated by this encoding. for (position, &left) in eligible.iter().enumerate() { for &right in &eligible[position + 1..] { - if !summary_mode_allowed( + if !summary_properties_allowed( node, &[left, right], - materialization, + properties, entries, data, query_time_results_retained, @@ -312,7 +300,7 @@ pub fn enumerate_candidate_configurations( } } let mut producer_sets = ProducerSetInterner::default(); - // Compatibility depends on consumer timing and producer mode/timing only. + // Compatibility depends on consumer timing and producer timing and lifetime only. // Evaluate each source configuration once per timing, then reuse this exact // index; reader eligibility remains expressed by separate graph constraints. let mut timing_index = Vec::with_capacity(source_configurations.len()); @@ -324,7 +312,7 @@ pub fn enumerate_candidate_configurations( { let mut compatible = Vec::new(); for &producer in configurations { - if compatible_timing(timing, &candidates[producer.0]) { + if candidates[producer.0].properties.readable_at(timing) { compatible.push(producer); } } @@ -337,11 +325,11 @@ pub fn enumerate_candidate_configurations( for candidate in &mut candidates { let mut requirements = Vec::new(); for input in &source.producer_nodes_per_input[candidate.operator_node.0] { - let key = (input.clone(), candidate.timing); + let key = (input.clone(), candidate.properties.timing()); let compatible_producers = if let Some(producer_candidates) = input_cache.get(&key) { producer_candidates.clone() } else { - let timing = match candidate.timing { + let timing = match candidate.properties.timing() { ExecutionTiming::QueryTime => 0, ExecutionTiming::IngestionTime => 1, }; @@ -391,16 +379,10 @@ fn per_entity_aggregate_executable(node: &OperatorNode) -> bool { } } -pub fn compatible_timing(consumer_timing: ExecutionTiming, producer: &PhysicalCandidate) -> bool { - consumer_timing == producer.timing - || (consumer_timing == ExecutionTiming::QueryTime - && matches!(producer.materialization, Materialization::MatAtIngestion(_))) -} - -fn summary_mode_allowed( +fn summary_properties_allowed( node: &OperatorNode, readers: &[usize], - mode: Materialization, + candidate_properties: PhysicalProperties, entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, @@ -415,10 +397,15 @@ fn summary_mode_allowed( return false; }; eligibility.range_compatibility.is_ok() - && match mode { - Materialization::NotMaterialized | Materialization::MatAtQuery(_) => true, - Materialization::MatAtIngestion(_) => eligibility.at_ingestion.is_ok(), - Materialization::MatAtQueryKeptAcrossEvaluations(_) => { + && match ( + candidate_properties.timing(), + candidate_properties.lifetime(), + ) { + (_, Lifetime::None | Lifetime::OneEvaluation(_)) => true, + (ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(_)) => { + eligibility.at_ingestion.is_ok() + } + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => { eligibility.may_keep_across_evaluations } } diff --git a/crates/physical-asap-optimization/src/catalog/factoring.rs b/crates/physical-asap-optimization/src/catalog/factoring.rs index 4ee9e4b68..abe4706b1 100644 --- a/crates/physical-asap-optimization/src/catalog/factoring.rs +++ b/crates/physical-asap-optimization/src/catalog/factoring.rs @@ -141,12 +141,12 @@ pub fn factor_terminal_readers( template.result_kind, &template.guarantee, template.timing, - template.materialization, + template.lifetime, &input.schema, input.result_kind, &input.guarantee, input.timing, - input.materialization, + input.lifetime, )) .map_err(|error| invalid(error.to_string()))?; if let Some(&previous) = classes.get(&key) { diff --git a/crates/physical-asap-optimization/src/catalog/inventory.rs b/crates/physical-asap-optimization/src/catalog/inventory.rs index cc8daf559..50a11f6a5 100644 --- a/crates/physical-asap-optimization/src/catalog/inventory.rs +++ b/crates/physical-asap-optimization/src/catalog/inventory.rs @@ -10,7 +10,6 @@ use std::collections::{HashMap, HashSet}; use std::rc::Rc; use asap_types::ir::OperatorNode; -use asap_types::physical::Materialization; use asap_types::stages::Memo; use asap_types::stages::MemoGroupId; @@ -21,7 +20,7 @@ use asap_types::stages::{ }; /// The memo's implementation candidates lowered to operator nodes, before -/// timing and materialization. Node IDs index +/// timing and lifetime. Node IDs index /// `operator_nodes_of_candidates_for_memo_groups`; they become /// [`asap_types::stages::OperatorNodeOfCandidateForMemoGroupId`]s of the /// configured candidates. @@ -278,11 +277,11 @@ impl ImmediateCandidateBuilder<'_> { if let Some(&existing) = self.private_nodes.get(&Rc::as_ptr(node)) { return Ok(existing); } - if node.timing.is_some() || node.materialization != Materialization::NotMaterialized { + if node.timing.is_some() || node.lifetime.is_kept() { return Err(CandidateInventoryError::Unsupported { group: self.owner.group.0 as usize, candidate: self.owner.index, - reason: "assigned execution timing or materialization", + reason: "assigned execution timing or lifetime", }); } let mut requirements = Vec::new(); diff --git a/crates/physical-asap-optimization/src/catalog/mod.rs b/crates/physical-asap-optimization/src/catalog/mod.rs index eb3069ead..cc55d52a9 100644 --- a/crates/physical-asap-optimization/src/catalog/mod.rs +++ b/crates/physical-asap-optimization/src/catalog/mod.rs @@ -1,5 +1,5 @@ //! Stage 2's physical candidates: implement each memo candidate's -//! operators, enumerate its timing and materialization, record which +//! operators, enumerate its timing and lifetime, record which //! candidates can produce each input, and prune what cannot be used //! ([`generate_physical_asap_memo_candidates`]); and realize one selected //! assignment as a physical plan (#1047). The output type, @@ -145,8 +145,7 @@ fn validate_candidates(physical: &PhysicalASAPMemoCandidates) -> Result<(), Stri #[cfg(feature = "test-support")] pub mod test_support { pub use super::configurations::{ - compatible_timing, enumerate_candidate_configurations, - may_keep_across_evaluations_per_sole_reader_query, + enumerate_candidate_configurations, may_keep_across_evaluations_per_sole_reader_query, }; pub use super::factoring::{ factor_terminal_readers, MemoGroupOutputKey, MemoGroupOutputToCompatibleProducersCache, diff --git a/crates/physical-asap-optimization/src/catalog/pruning.rs b/crates/physical-asap-optimization/src/catalog/pruning.rs index 4cde4cb9e..6a26ecb16 100644 --- a/crates/physical-asap-optimization/src/catalog/pruning.rs +++ b/crates/physical-asap-optimization/src/catalog/pruning.rs @@ -25,8 +25,7 @@ pub fn prune(configured: PhysicalASAPMemoCandidates) -> Result = selected + // Each selected node's assignment: its properties when it is kept, + // `None` when it is not. + let assignments: Vec<_> = selected .candidate_of_node .iter() - .map(|id| physical_candidates.candidates[id.0].materialization) + .map(|id| { + let properties = physical_candidates.candidates[id.0].properties; + properties.lifetime().is_kept().then_some(properties) + }) .collect(); let mut node_by_pointer = HashMap::new(); for (node, operator_node) in rebuilt.operator_node_of_selected_node.iter().enumerate() { @@ -50,7 +55,7 @@ pub fn materialize_selected_candidates( } let roots = restore_query_roots(original_roots, &rebuilt.outputs)?; let mut assignment_error = None; - let mut seen = vec![false; materializations.len()]; + let mut seen = vec![false; assignments.len()]; let physical = optimize_physical_asap_chosen( "selected-candidate-connections", &roots, @@ -61,13 +66,13 @@ pub fn materialize_selected_candidates( let node = node_by_pointer.get(&logical).copied(); let requested = if let Some(node) = node { seen[node] = true; - materializations[node] + assignments[node] } else { - Materialization::NotMaterialized + None }; if !options.contains(&requested) { let message = format!( - "selected materialization {requested:?} is not offered for selected node {node:?}" + "selected kept output {requested:?} is not offered for selected node {node:?}" ); assignment_error = Some(if node.is_some() { PhysicalCandidateError::RejectedAssignment(message) @@ -92,8 +97,8 @@ pub fn materialize_selected_candidates( physical.dag.validate().map_err(|error| error.to_string())?; let physical_outputs = ordered_output_references(&physical.roots); let identities = paired_node_identities(&rebuilt.outputs, &physical_outputs)?; - for (node, mode) in materializations.iter().enumerate() { - if *mode != Materialization::NotMaterialized && !seen[node] { + for (node, kept) in assignments.iter().enumerate() { + if kept.is_some() && !seen[node] { // The decoder already established node identity. Stage 2 did // not offer this selected node (e.g. a lower shared non-summary), // so the assignment is infeasible rather than an adapter failure. @@ -111,9 +116,10 @@ pub fn materialize_selected_candidates( .get(&Rc::as_ptr(&operator_node)) .cloned() .ok_or_else(|| format!("selected node {node} has no physical identity"))?; - if physical.materialization != materializations[node] { + let lifetime = assignments[node].map_or(Lifetime::None, |kept| kept.lifetime()); + if physical.lifetime != lifetime { return Err(format!( - "selected node {node} materialization changed during physical reconstruction" + "selected node {node} lifetime changed during physical reconstruction" )); } Ok(physical) @@ -163,7 +169,7 @@ impl AssignmentRealizer for Stage2AssignmentRealizer<'_> { .iter() .zip(&realized.operator_node_of_selected_node) { - let timing = physical.candidates[id.0].timing; + let timing = physical.candidates[id.0].properties.timing(); if node.timing != Some(timing) { return Err(PhysicalCandidateError::InvalidOrUnsupported(format!( "candidate {} requested timing {timing:?}, Stage 2 produced {:?}", @@ -243,9 +249,7 @@ mod tests { let producer = producer_candidates .iter() .copied() - .find(|s| { - physical.candidates[s.0].materialization == Materialization::NotMaterialized - }) + .find(|s| !physical.candidates[s.0].properties.lifetime().is_kept()) .unwrap_or(producer_candidates[0]); let producer = select_from(physical, producer, selected); selected.edges.push(SelectedEdge { diff --git a/crates/physical-asap-optimization/src/lib.rs b/crates/physical-asap-optimization/src/lib.rs index aed2e101c..a6e7a17ba 100644 --- a/crates/physical-asap-optimization/src/lib.rs +++ b/crates/physical-asap-optimization/src/lib.rs @@ -21,16 +21,16 @@ //! So is the highest node of each other sub-DAG that two or more queries //! read (e.g. a `Scan` that a 1 m and a 5 m window read): one a root or a //! node only one query reads consumes. Such a node has only -//! `NotMaterialized` and `MatAtQuery(Memory)`, so a shared sub-DAG adds one +//! not kept and `OneEvaluation(Memory)`, so a shared sub-DAG adds one //! option, not one per node. A summary build has up to four options: //! -//! * `NotMaterialized`: rebuilt at query time by every query that reads it; -//! * `MatAtIngestion(Memory)`: maintained as data arrives and kept for the +//! * not kept: rebuilt at query time by every query that reads it; +//! * ingestion-time `AcrossEvaluations(Memory)`: maintained as data arrives and kept for the //! queries, when the build is eligible (`IngestionPruneReason`); -//! * `MatAtQuery(Memory)`: built once at query time for every query of one +//! * `OneEvaluation(Memory)`: built once at query time for every query of one //! evaluation that reads it and reused only within that evaluation, //! offered for a build two or more queries read; -//! * `MatAtQueryKeptAcrossEvaluations(Memory)`: built at query time and +//! * query-time `AcrossEvaluations(Memory)`: built at query time and //! kept across evaluations (#509 Example 4's B3), offered when the //! deployment keeps query-time results (the caller's //! `query_time_results_retained`) for a @@ -41,9 +41,9 @@ //! //! A build at ingestion time needs every build below it at ingestion time too //! (#509 Algorithm 3, line 13), and every shared non-summary node below it -//! `NotMaterialized`; other assignments are not generated. Every +//! not kept; other assignments are not generated. Every //! other combination of options is one physical candidate, the -//! all-`NotMaterialized` one first: nothing is capped. A node that one +//! all-not-kept one first: nothing is capped. A node that one //! query reads at ingestion time and another at query time is copied, one //! copy per timing (`split_shared_by_timing`). //! @@ -132,9 +132,9 @@ use asap_types::ir::{ NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, ScalarExpr, SchemaDerivationError, SortKey, }; -use asap_types::physical::Materialization; use asap_types::physical::Medium; use asap_types::physical::PhysicalWorkloadPlan; +use asap_types::physical::{Lifetime, PhysicalProperties}; use asap_types::workload::{ DataArrival, DataWorkload, Predictability, QueryRecurrence, QueryWorkloadEntry, RepeatedDemand, }; @@ -324,10 +324,10 @@ fn summary_reader_eligibility( /// /// | materialization candidate | readers | options | /// |----------------------------------|---------|---------------------------------| -/// | Kll ×5 tumbling windows (q1) | q1 | NotMaterialized, MatAtIngestion | -/// | Max acc ×5 tumbling windows (q2) | q2 | NotMaterialized, MatAtIngestion | +/// | Kll ×5 tumbling windows (q1) | q1 | not kept, kept at ingestion time | +/// | Max acc ×5 tumbling windows (q2) | q2 | not kept, kept at ingestion time | /// -/// One read by two or more queries also gets `MatAtQuery` (built once per +/// One read by two or more queries also gets `OneEvaluation` (built once per /// evaluation and reused), and so does the highest node of a shared /// non-summary sub-DAG, e.g. a `Scan` both queries read when Stage 1 /// shares it. The physical candidates are the product of the @@ -342,31 +342,29 @@ pub(crate) struct MaterializationCandidate { pub(crate) node: Rc, /// The queries (indices into the roots) that read it. pub(crate) readers: Vec, - /// `Ok` when `MatAtIngestion` is an option. + /// `Ok` when kept at ingestion time is an option. pub(crate) at_ingestion: Result<(), IngestionPruneReason>, - /// Whether `MatAtQueryKeptAcrossEvaluations` is an option: the + /// Whether query-time `AcrossEvaluations` is an option: the /// deployment keeps query-time results and it is a tumbling-window chain /// that builds one new tumbling window per evaluation. pub(crate) may_keep_across_evaluations: bool, } impl MaterializationCandidate { - /// Its options, `NotMaterialized` first: `MatAtIngestion` when eligible, - /// `MatAtQuery` when two or more queries read it, and - /// `MatAtQueryKeptAcrossEvaluations` when it may be kept across + /// Its options, not kept first: kept at ingestion time when eligible, + /// `OneEvaluation` when two or more queries read it, and + /// query-time `AcrossEvaluations` when it may be kept across /// evaluations. - pub(crate) fn options(&self) -> Vec { - let mut options = vec![Materialization::NotMaterialized]; + pub(crate) fn options(&self) -> Vec> { + let mut options = vec![None]; if self.at_ingestion.is_ok() { - options.push(Materialization::MatAtIngestion(Medium::Memory)); + options.push(Some(kept_across_evaluations_at_ingestion())); } if self.readers.len() > 1 { - options.push(Materialization::MatAtQuery(Medium::Memory)); + options.push(Some(kept_for_one_evaluation())); } if self.may_keep_across_evaluations { - options.push(Materialization::MatAtQueryKeptAcrossEvaluations( - Medium::Memory, - )); + options.push(Some(kept_across_evaluations_at_query_time())); } options } @@ -414,7 +412,7 @@ pub(crate) fn builds_one_tumbling_window_per_evaluation<'a>( /// Stage 2 for one CandidateLogicalASAPDAG: implement every operator /// (physical operator implementation), then one physical candidate per -/// materialization assignment of its mat_candidates, the all-`NotMaterialized` one +/// materialization assignment of its mat_candidates, the all-not-kept one /// first. `entries[i]` is the workload entry of query `i` (`roots[i]`): /// its recurrence and predictability decide whether state may be kept from /// ingestion time; a missing entry is unknown. `id` is left empty for the @@ -458,7 +456,7 @@ pub fn optimize_physical_asap_assigned( entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, - choose: &mut dyn FnMut(&[usize]) -> Option, + choose: &mut dyn FnMut(&[usize]) -> Option>, ) -> Result, PhysicalASAPOptimizationError> { optimize_physical_asap_chosen( from_logical, @@ -473,8 +471,12 @@ pub fn optimize_physical_asap_assigned( /// [`optimize_physical_asap_chosen`]'s choice per materialization /// candidate: from the logical node it implements, its readers and its /// options. `None` rejects the assignment. -pub(crate) type ChooseMaterialization<'a> = - dyn FnMut(*const OperatorNode, &[usize], &[Materialization]) -> Option + 'a; +pub(crate) type ChooseMaterialization<'a> = dyn FnMut( + *const OperatorNode, + &[usize], + &[Option], + ) -> Option> + + 'a; /// Stage 2 for one CandidateLogicalASAPDAG and one materialization /// assignment chosen node by node: `choose(logical, readers, options)` @@ -526,17 +528,13 @@ fn assigned_candidate( from_logical: &str, implemented: &[QueryRoot], mat_candidates: &[MaterializationCandidate], - assignment: Vec, + assignment: Vec>, ) -> Result { - let materialized: Vec<_> = mat_candidates - .iter() - .zip(&assignment) - .filter(|(_, m)| **m != Materialization::NotMaterialized) - .map(|(mat_candidate, m)| (mat_candidate, *m)) - .collect(); - let mut options = MaterializationAssignment::with_default(Materialization::NotMaterialized); - for (mat_candidate, materialization) in &materialized { - options.set(&mat_candidate.node, *materialization); + let mut options = MaterializationAssignment::default(); + for (mat_candidate, kept) in mat_candidates.iter().zip(&assignment) { + if kept.is_some() { + options.set(&mat_candidate.node, *kept); + } } let operators: Vec> = implemented .iter() @@ -556,7 +554,7 @@ fn assigned_candidate( Ok(apply_materialization_timings(node, &options, &mut timing)?) })?; let dag = compile_physical_asap_workload_with_node_ids(&timed)?.dag; - let materialization = dag + let lifetime = dag .nodes .iter() .filter(|n| { @@ -565,16 +563,16 @@ fn assigned_candidate( Operator::ASAP( ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } ) - ) || n.materialization != Materialization::NotMaterialized + ) || n.lifetime.is_kept() }) - .map(|n| (n.id, n.materialization)) + .map(|n| (n.id, n.lifetime)) .collect(); Ok(PhysicalWorkloadPlan { id: String::new(), from_logical: from_logical.to_string(), roots: timed, dag, - materialization, + lifetime, }) } @@ -661,7 +659,7 @@ fn is_summary_build(node: &OperatorNode) -> bool { /// discovery order, then every highest shared non-summary node, in /// discovery order. A shared node is one two or more queries read; the /// highest are those a root or an unshared node reads (e.g. a `Scan` that -/// two windows read). Only a highest one is offered `MatAtQuery`, so a +/// two windows read). Only a highest one is offered `OneEvaluation`, so a /// shared sub-DAG adds one candidate, not one per node. pub(crate) fn materialization_candidates( roots: &[QueryRoot], @@ -711,10 +709,9 @@ pub(crate) fn materialization_candidates( summary_reader_eligibility(node, &readers, entries, data, query_time_results_retained); let at_ingestion = eligibility.at_ingestion.and_then(|()| { // Only this build and the builds below it at ingestion time. - let mut trial = - MaterializationAssignment::with_default(Materialization::NotMaterialized); + let mut trial = MaterializationAssignment::default(); for &v in below[c].iter().chain([&c]) { - trial.set(&nodes[v], Materialization::MatAtIngestion(Medium::Memory)); + trial.set(&nodes[v], Some(kept_across_evaluations_at_ingestion())); } apply_materialization_timings(node, &trial, &mut NodeToTimedNodeCache::new()) .map(|_| ()) @@ -943,43 +940,46 @@ fn candidates_below(nodes: &[Rc]) -> Vec> { /// Whether, below every ingestion-time build of `assignment`, every build /// is at ingestion time too and every shared non-summary node is -/// `NotMaterialized`: ingestion work reads it as it arrives, and its +/// not kept: ingestion work reads it as it arrives, and its /// query-time readers read a copy ([`split_shared_by_timing`]). -/// Simplification: that copy is not offered `MatAtQuery` even when two +/// Simplification: that copy is not offered `OneEvaluation` even when two /// query-time readers remain. `below` is [`candidates_below`] of /// `mat_candidates`. fn down_closed( mat_candidates: &[MaterializationCandidate], below: &[Vec], - assignment: &[Materialization], + assignment: &[Option], ) -> bool { - let at_ingestion = |m: &Materialization| m.timing() == ExecutionTiming::IngestionTime; + let at_ingestion = |kept: &Option| { + kept.is_some_and(|p| p.timing() == ExecutionTiming::IngestionTime) + }; assignment.iter().enumerate().all(|(c, m)| { !at_ingestion(m) || below[c].iter().all(|&v| { if is_summary_build(&mat_candidates[v].node) { at_ingestion(&assignment[v]) } else { - assignment[v] == Materialization::NotMaterialized + assignment[v].is_none() } }) }) } /// Every assignment of an option to each materialization candidate (mixed -/// radix, the last varying fastest, all `NotMaterialized` first) that is +/// radix, the last varying fastest, all not kept first) that is /// [`down_closed`]. #[cfg(any(test, feature = "reference-pricer"))] fn materialization_assignments( mat_candidates: &[MaterializationCandidate], -) -> impl Iterator> + '_ { - let options: Vec> = mat_candidates.iter().map(|c| c.options()).collect(); +) -> impl Iterator>> + '_ { + let options: Vec>> = + mat_candidates.iter().map(|c| c.options()).collect(); let nodes: Vec<_> = mat_candidates.iter().map(|c| Rc::clone(&c.node)).collect(); let below = candidates_below(&nodes); let mut digits = Some(vec![0usize; mat_candidates.len()]); std::iter::from_fn(move || loop { let current = digits.as_mut()?; - let assignment: Vec = current + let assignment: Vec> = current .iter() .zip(&options) .map(|(&d, options)| options[d]) @@ -1195,6 +1195,39 @@ pub mod test_support { } } +/// `timing` and `lifetime`, a pair Stage 2 only builds when valid. +pub(crate) fn physical_properties( + timing: ExecutionTiming, + lifetime: Lifetime, +) -> PhysicalProperties { + PhysicalProperties::new(timing, lifetime).expect("Stage 2 builds only valid pairs") +} + +/// Query time, kept in memory until the evaluation's readers finish. +pub(crate) fn kept_for_one_evaluation() -> PhysicalProperties { + physical_properties( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ) +} + +/// Ingestion time, kept in memory until a query reads it. +pub(crate) fn kept_across_evaluations_at_ingestion() -> PhysicalProperties { + physical_properties( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) +} + +/// Query time, kept in memory across evaluations (a tumbling-window chain +/// that builds its newest window at each evaluation). +pub(crate) fn kept_across_evaluations_at_query_time() -> PhysicalProperties { + physical_properties( + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) +} + #[cfg(test)] mod tests { use super::*; @@ -1257,7 +1290,7 @@ mod tests { ); } - /// The all-`NotMaterialized` candidate, with no workload declared. + /// The all-not-kept candidate, with no workload declared. fn first_candidate(roots: &[QueryRoot]) -> PhysicalWorkloadPlan { optimize_physical_asap("L1", roots, &[], &DataWorkload::default(), false) .unwrap() @@ -1573,15 +1606,15 @@ mod tests { pass2_candidates.pop().unwrap().roots.unwrap().remove(0) } - const AT_INGESTION: Materialization = Materialization::MatAtIngestion(Medium::Memory); + const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); - /// The options `candidate` chose other than `NotMaterialized`, by node. - fn materialized(candidate: &PhysicalWorkloadPlan) -> Vec { + /// The lifetimes `candidate` chose other than `None`, by node. + fn materialized(candidate: &PhysicalWorkloadPlan) -> Vec { candidate - .materialization + .lifetime .values() .copied() - .filter(|m| *m != Materialization::NotMaterialized) + .filter(|lifetime| lifetime.is_kept()) .collect() } @@ -1779,14 +1812,12 @@ mod tests { .nodes .iter() .all(|n| n.output_state.timing == ExecutionTiming::QueryTime)); - assert_eq!(materialized(b1), [AT_INGESTION]); + assert_eq!(materialized(b1), [KEPT_ACROSS]); let [chain] = &node_of(b1, "SummaryTumblingWindowChain")[..] else { panic!("one chain") }; - assert_eq!( - chain.materialization, - Materialization::MatAtIngestion(Medium::Memory) - ); + assert_eq!(chain.lifetime, KEPT_ACROSS); + assert_eq!(chain.timing, Some(ExecutionTiming::IngestionTime)); for below in OperatorNode::reachable(chain) { assert_eq!(below.timing, Some(ExecutionTiming::IngestionTime)); } @@ -2083,7 +2114,7 @@ mod tests { false, ) .unwrap(); - assert_eq!(materialized(&candidates[1]), [AT_INGESTION]); + assert_eq!(materialized(&candidates[1]), [KEPT_ACROSS]); // The same build with a filter. let QueryRoot::Operator(node) = &root else { @@ -2215,7 +2246,7 @@ mod tests { } /// A build two queries read is also offered built once per evaluation - /// for both (`MatAtQuery`); a build one query reads is not. + /// for both (`OneEvaluation`); a build one query reads is not. #[test] fn a_build_two_queries_read_may_be_built_once_per_evaluation() { let QueryRoot::Operator(p99) = summary_root("quantile_over_time(0.99, m[1m])") else { @@ -2238,21 +2269,18 @@ mod tests { assert_eq!(candidates.len(), 2); assert_eq!( materialized(&candidates[1]), - [Materialization::MatAtQuery(Medium::Memory)] + [Lifetime::OneEvaluation(Medium::Memory)] ); let [build] = &node_of(&candidates[1], "SummaryAgg")[..] else { panic!("one shared build") }; - assert_eq!( - build.materialization, - Materialization::MatAtQuery(Medium::Memory) - ); + assert_eq!(build.lifetime, Lifetime::OneEvaluation(Medium::Memory)); } /// Two queries share one scan: one reads it through tumbling windows maintained at /// ingestion time, the other at query time. The scan is split, one copy /// per timing; with nothing materialized it stays one node. The shared - /// scan may also be built once per evaluation (`MatAtQuery`), but not + /// scan may also be built once per evaluation (`OneEvaluation`), but not /// under ingestion-time tumbling windows, where only one query reads it at query /// time. #[test] @@ -2298,12 +2326,12 @@ mod tests { .nodes .iter() .filter(|n| matches!(n.payload, Payload::NonASAP(NonASAPOp::Scan { .. }))) - .map(|n| (n.output_state.timing, n.materialization)) + .map(|n| (n.output_state.timing, n.lifetime)) .collect(); scans.sort_by_key(|(t, _)| *t == ExecutionTiming::QueryTime); scans }; - let not_materialized = Materialization::NotMaterialized; + let not_materialized = Lifetime::None; assert_eq!( scans(&candidates[0]), [(ExecutionTiming::QueryTime, not_materialized)] @@ -2312,7 +2340,7 @@ mod tests { scans(&candidates[1]), [( ExecutionTiming::QueryTime, - Materialization::MatAtQuery(Medium::Memory) + Lifetime::OneEvaluation(Medium::Memory) )] ); assert_eq!( @@ -2325,7 +2353,7 @@ mod tests { } /// Only the highest shared non-summary nodes are materialization - /// candidates, each with `NotMaterialized` and `MatAtQuery` only: a + /// candidates, each with not kept and `OneEvaluation` only: a /// 5 m range two queries read (not the scan below it, which only that /// shared range reads for them), and the scan, which a third query /// also reads through its own 1 m range. @@ -2367,10 +2395,7 @@ mod tests { .iter() .map(|c| (c.node.operator.kind_name(), c.readers.clone(), c.options())) .collect(); - let options = vec![ - Materialization::NotMaterialized, - Materialization::MatAtQuery(Medium::Memory), - ]; + let options = vec![None, Some(kept_for_one_evaluation())]; assert_eq!( found, [ diff --git a/crates/physical-asap-optimization/src/split_by_timing.rs b/crates/physical-asap-optimization/src/split_by_timing.rs index 72dad6d63..9a71eb28d 100644 --- a/crates/physical-asap-optimization/src/split_by_timing.rs +++ b/crates/physical-asap-optimization/src/split_by_timing.rs @@ -85,7 +85,7 @@ pub fn split_shared_by_timing( OperatorNode::with_schema(operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } else { Rc::clone(node) @@ -108,8 +108,8 @@ pub fn split_shared_by_timing( .collect(); let mut remapped = assignment.clone(); for (original, copy) in copies.values() { - if let Some(materialization) = assignment.get(original) { - remapped.set(copy, materialization); + if let Some(kept) = assignment.get(original) { + remapped.set(copy, kept); } } (split, remapped) @@ -130,9 +130,14 @@ mod tests { use asap_types::ir::{ apply_materialization_timings, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, }; - use asap_types::physical::{Materialization, Medium}; + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; - const AT_INGESTION: Materialization = Materialization::MatAtIngestion(Medium::Memory); + const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); + + /// Kept at ingestion time across evaluations. + fn at_ingestion() -> Option { + PhysicalProperties::new(ExecutionTiming::IngestionTime, KEPT_ACROSS).ok() + } fn scan() -> Rc { OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { @@ -242,7 +247,7 @@ mod tests { assert_eq!( apply_materialization_timings( &root, - &MaterializationAssignment::with_default(AT_INGESTION), + &MaterializationAssignment::with_default(at_ingestion()), &mut NodeToTimedNodeCache::new() ) .err(), @@ -253,7 +258,7 @@ mod tests { ); let (split, assignment) = split_shared_by_timing( std::slice::from_ref(&root), - &MaterializationAssignment::with_default(AT_INGESTION), + &MaterializationAssignment::with_default(at_ingestion()), ); assert!(apply_materialization_timings( &split[0], @@ -274,7 +279,7 @@ mod tests { })) .unwrap(); let mut assignment = MaterializationAssignment::default(); - assignment.set(&summary, AT_INGESTION); + assignment.set(&summary, at_ingestion()); let (split, assignment) = split_shared_by_timing(std::slice::from_ref(&root), &assignment); let timed = apply_materialization_timings(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) @@ -284,7 +289,7 @@ mod tests { summary.operator, Operator::ASAP(ASAPOp::SummaryAgg { .. }) )); - assert_eq!(summary.materialization, AT_INGESTION); + assert_eq!(summary.lifetime, KEPT_ACROSS); assert_eq!(summary.timing, Some(ExecutionTiming::IngestionTime)); } @@ -305,7 +310,7 @@ mod tests { concat(vec![raw, Rc::clone(&common)]), ]; let mut assignment = MaterializationAssignment::default(); - assignment.set(&summary, AT_INGESTION); + assignment.set(&summary, at_ingestion()); let timed_unsplit = { let mut cache = NodeToTimedNodeCache::new(); roots @@ -325,7 +330,7 @@ mod tests { .map(|root| apply_materialization_timings(root, &assignment, &mut cache).unwrap()) .collect(); let summary = child(&child(&child(&timed[0]))); - assert_eq!(summary.materialization, AT_INGESTION); + assert_eq!(summary.lifetime, KEPT_ACROSS); assert_eq!(child(&summary).timing, Some(ExecutionTiming::IngestionTime)); assert_eq!( child(&child(&timed[1])).timing, @@ -352,9 +357,9 @@ mod tests { .with_timing(Some(ExecutionTiming::QueryTime)), ); let mut assignment = MaterializationAssignment::default(); - assignment.set(&summary, AT_INGESTION); - assignment.set(&state, AT_INGESTION); - assignment.set(&read, AT_INGESTION); + assignment.set(&summary, at_ingestion()); + assignment.set(&state, at_ingestion()); + assignment.set(&read, at_ingestion()); let (split, assignment) = split_shared_by_timing(&[pair, read], &assignment); let mut cache = NodeToTimedNodeCache::new(); let timed: Result, _> = split @@ -367,7 +372,7 @@ mod tests { ExecutionDataStateError::MaterializationConflictsWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - materialization: AT_INGESTION, + assigned: at_ingestion().unwrap(), } ) ); diff --git a/crates/plan-selection/src/groups.rs b/crates/plan-selection/src/groups.rs index 1421f5d2a..6c917282e 100644 --- a/crates/plan-selection/src/groups.rs +++ b/crates/plan-selection/src/groups.rs @@ -50,7 +50,7 @@ //! ## Dominance (exact under cost model 1) //! //! Candidate `k` is deleted when another candidate `k'` (the *dominating* candidate): -//! - is in the same memo group, at the same timing and materialization, +//! - is in the same memo group, at the same timing and lifetime, //! with the same held state; //! - has the same producer candidates per input, the same readers (every //! (reader candidate, input) that may read `k` may read `k'`, and nothing @@ -114,7 +114,7 @@ use asap_types::ir::properties::execution_data_state::{DataPrimitive, ExecutionD use asap_types::ir::properties::{AccuracyGuarantee, ExecutionTiming}; use asap_types::ir::schema::{FieldDataType, Schema}; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode}; -use asap_types::physical::Materialization; +use asap_types::physical::{Lifetime, PhysicalProperties}; use asap_types::stages::{ output_references, MemoGroupId, OperatorNodeOfCandidateForMemoGroupId, PhysicalASAPMemoCandidates, @@ -252,7 +252,7 @@ pub(crate) struct CandidateUsage { pub(crate) peak_memory_bytes: u64, pub(crate) disk_bytes: u64, /// Query-time memory held while an evaluation reading it runs (a - /// `MatAtQuery` state, or a not-materialized node's working memory). + /// `OneEvaluation` state, or a not-materialized node's working memory). pub(crate) held_bytes: u64, /// Raw data a query-time scan keeps on disk. pub(crate) raw_data_kept_bytes: u64, @@ -324,30 +324,30 @@ pub(crate) enum UnusableReason { } /// Where a candidate runs (#1095 §2.0, "Memo groups and execution -/// contexts"), by its materialization alone, as `asap_cost::plan_cost` +/// contexts"), by its timing and lifetime, as `asap_cost::plan_cost` /// counts its executions: #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) enum RunKind { - /// `NotMaterialized` at query time: computed once in each execution + /// Not kept (lifetime `None`) at query time: computed once in each execution /// context (a query evaluation, or a shared query-time candidate's /// inputs) that selects it. PerContext, - /// `NotMaterialized` at ingestion time: runs in the ingestion pipeline + /// Not kept (lifetime `None`) at ingestion time: runs in the ingestion pipeline /// `I_r` of its readers' refresh window `r`, once per second of /// arriving data for all of them. Ingestion, - /// Materialized (`MatAtIngestion`, `MatAtQuery`, - /// `MatAtQueryKeptAcrossEvaluations`): selected once, its own execution - /// context for its inputs, charged once. + /// Kept (lifetime `OneEvaluation` or `AcrossEvaluations`, at either + /// timing): selected once, its own execution context for its inputs, + /// charged once. Shareable, } -/// The [`RunKind`] of a candidate at `timing` and `materialization`. -pub(crate) fn run_kind(timing: ExecutionTiming, materialization: Materialization) -> RunKind { - match (materialization, timing) { - (Materialization::NotMaterialized, ExecutionTiming::QueryTime) => RunKind::PerContext, - (Materialization::NotMaterialized, ExecutionTiming::IngestionTime) => RunKind::Ingestion, - _ => RunKind::Shareable, +/// The [`RunKind`] of a candidate with `properties`. +pub(crate) fn run_kind(properties: PhysicalProperties) -> RunKind { + match (properties.lifetime(), properties.timing()) { + (Lifetime::None, ExecutionTiming::QueryTime) => RunKind::PerContext, + (Lifetime::None, ExecutionTiming::IngestionTime) => RunKind::Ingestion, + (Lifetime::OneEvaluation(_) | Lifetime::AcrossEvaluations(_), _) => RunKind::Shareable, } } @@ -356,7 +356,7 @@ pub(crate) fn run_kind(timing: ExecutionTiming, materialization: Materialization /// roots give the group's result; an implementation's private nodes /// (`is_implementation_root == false`) give an intermediate result of /// their own, so each private operator node is its own slot (its -/// candidates differ only in timing and materialization). +/// candidates differ only in timing and lifetime). /// /// The memo group graph is not acyclic: a widened scan puts a `Project` in /// the memo group of the scan it reads, so a group's candidate may read @@ -432,7 +432,7 @@ impl CandidateLinks { let kind: Vec = physical .candidates .iter() - .map(|candidate| run_kind(candidate.timing, candidate.materialization)) + .map(|candidate| run_kind(candidate.properties)) .collect(); // With one candidate per result slot per context, a candidate that // runs in a context cannot read its own slot there (only a self-loop @@ -685,7 +685,7 @@ pub(crate) enum ContextKind { /// Which ingestion pipeline `I_r` (#1095 §2.5 O3(b)): the deployment /// refreshes the ingestion-time views of one refresh window in one run, so -/// `asap_cost::execution_demand::computations` charges a `NotMaterialized` +/// `asap_cost::execution_demand::computations` charges a not-kept /// ingestion-time node once per refresh window of the views reading it. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) enum IngestionPipeline { @@ -722,7 +722,8 @@ fn refresh_windows( .map(PhysicalCandidateId) .filter(|&class| { links.is_shareable(class) - && physical.candidates[class.0].timing == ExecutionTiming::IngestionTime + && physical.candidates[class.0].properties.timing() + == ExecutionTiming::IngestionTime }) .collect(); let dag = dag_below(physical, links, &views); @@ -957,7 +958,8 @@ pub(crate) fn execution_contexts( } pending.sort_unstable(); for class in pending { - let at_query_time = physical.candidates[class.0].timing == ExecutionTiming::QueryTime; + let at_query_time = + physical.candidates[class.0].properties.timing() == ExecutionTiming::QueryTime; let mut context = ExecutionContext { kind: ContextKind::Shared(class), at_query_time, @@ -1048,14 +1050,14 @@ fn catalog_node( id: class.0, payload, output_state: ExecutionDataState { - timing: candidate.timing, + timing: candidate.properties.timing(), primitive: if node.asap().and_then(ASAPOp::produced_state).is_some() { DataPrimitive::SummaryState } else { DataPrimitive::Raw }, }, - materialization: candidate.materialization, + lifetime: candidate.properties.lifetime(), output_schema: node.schema.clone(), guarantee: node.guarantee.clone(), retention_ms: None, @@ -1090,10 +1092,8 @@ fn window_read_through(path: &[&PhysicalASAPDAGNode]) -> ScanWindow { Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { tumbling_window_width_ms, .. - }) if matches!( - node.materialization, - Materialization::MatAtQueryKeptAcrossEvaluations(_) - ) => + }) if node.output_state.timing == ExecutionTiming::QueryTime + && matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) => { u128::from(*tumbling_window_width_ms) } @@ -1307,11 +1307,10 @@ fn retained_pane_options( ) -> Vec { let node = &nodes[chain.0]; let kept = matches!( - (&node.payload, node.materialization), + (&node.payload, node.lifetime), ( Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), - Materialization::MatAtIngestion(_) - | Materialization::MatAtQueryKeptAcrossEvaluations(_) + Lifetime::AcrossEvaluations(_) ) ); if !kept { @@ -1938,8 +1937,7 @@ pub(crate) struct DominanceProfile<'a> { #[derive(Debug, Clone, PartialEq)] pub(crate) struct DominanceKey<'a> { pub(crate) group: MemoGroupId, - pub(crate) timing: ExecutionTiming, - pub(crate) materialization: Materialization, + pub(crate) properties: PhysicalProperties, pub(crate) shareable: bool, pub(crate) producer_candidates_per_input: &'a [Vec], pub(crate) readers: Vec<(PhysicalCandidateId, usize)>, @@ -1990,8 +1988,7 @@ fn dominance_profiles<'a>( DominanceProfile { same: DominanceKey { group: physical.memo_group_of(copy), - timing: candidate.timing, - materialization: candidate.materialization, + properties: candidate.properties, shareable: links.is_shareable(copy), producer_candidates_per_input: producers_per_input, readers: std::mem::take(&mut readers[class]), @@ -2102,15 +2099,10 @@ pub(crate) fn prune_dominated_candidates( ) -> Vec { // Only candidates with equal keys can dominate each other. let mut buckets: Vec> = Vec::new(); - let mut bucket_of_key: HashMap<(MemoGroupId, ExecutionTiming, Materialization), Vec> = - HashMap::new(); + let mut bucket_of_key: HashMap<(MemoGroupId, PhysicalProperties), Vec> = HashMap::new(); for (class, profile) in profiles.iter().enumerate() { let candidates = bucket_of_key - .entry(( - profile.same.group, - profile.same.timing, - profile.same.materialization, - )) + .entry((profile.same.group, profile.same.properties)) .or_default(); match candidates .iter() diff --git a/crates/plan-selection/src/groups/accuracy_positions.rs b/crates/plan-selection/src/groups/accuracy_positions.rs index fa81af61f..ec1f840a7 100644 --- a/crates/plan-selection/src/groups/accuracy_positions.rs +++ b/crates/plan-selection/src/groups/accuracy_positions.rs @@ -528,7 +528,7 @@ impl Checker<'_> { } /// `node` rebuilt over each combination of `per_input`'s outputs, with its -/// timing and materialization and its guarantee composed again; outputs the +/// timing and lifetime and its guarantee composed again; outputs the /// same for their readers kept once. fn rebuilt(node: &Rc, per_input: &[Vec>], keys: &mut Keys) -> Built { let combinations = combinations(per_input); @@ -543,7 +543,7 @@ fn rebuilt(node: &Rc, per_input: &[Vec>], keys: & rebuilt .with_guarantee(guarantee) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), )); } Ok(distinct_for_readers(outputs, keys)) diff --git a/crates/plan-selection/src/groups/tests.rs b/crates/plan-selection/src/groups/tests.rs index f9c2ce4ee..82df42489 100644 --- a/crates/plan-selection/src/groups/tests.rs +++ b/crates/plan-selection/src/groups/tests.rs @@ -76,14 +76,18 @@ pub(super) fn catalog( ) } -/// One candidate of operator node `node` at query time, not materialized, +/// At query time, not kept. +pub(super) fn query_time_not_kept() -> PhysicalProperties { + PhysicalProperties::new(ExecutionTiming::QueryTime, Lifetime::None).unwrap() +} + +/// One candidate of operator node `node` at query time, not kept, /// reading `producers` per input, that may produce a query's output when /// `output`. pub(super) fn candidate(node: usize, producers: &[&[usize]], output: bool) -> PhysicalCandidate { PhysicalCandidate { operator_node: OperatorNodeOfCandidateForMemoGroupId(node), - timing: ExecutionTiming::QueryTime, - materialization: Materialization::NotMaterialized, + properties: query_time_not_kept(), producer_candidates_per_input: producers .iter() .map(|input| { @@ -174,8 +178,7 @@ fn dominance_needs_every_condition() { OperatorKindForReaders::Other(std::mem::discriminant(&rows_node(1).operator), "Values"); let key = DominanceKey { group: MemoGroupId(3), - timing: ExecutionTiming::QueryTime, - materialization: Materialization::NotMaterialized, + properties: query_time_not_kept(), shareable: false, producer_candidates_per_input: &producers, readers: vec![(PhysicalCandidateId(9), 0)], @@ -209,14 +212,19 @@ fn dominance_needs_every_condition() { ( "timing", DominanceKey { - timing: ExecutionTiming::IngestionTime, + properties: PhysicalProperties::new(ExecutionTiming::IngestionTime, Lifetime::None) + .unwrap(), ..key.clone() }, ), ( - "materialization", + "lifetime", DominanceKey { - materialization: Materialization::MatAtQuery(Medium::Memory), + properties: PhysicalProperties::new( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ) + .unwrap(), ..key.clone() }, ), @@ -371,8 +379,7 @@ fn pruning_keeps_the_smallest_equal_class_and_incomparable_ones() { let schema = rows_node(1).schema.clone(); let key = DominanceKey { group: MemoGroupId(0), - timing: ExecutionTiming::QueryTime, - materialization: Materialization::NotMaterialized, + properties: query_time_not_kept(), shareable: false, producer_candidates_per_input: &producers, readers: Vec::new(), @@ -486,7 +493,11 @@ fn shared_middle() -> PhysicalASAPMemoCandidates { let candidates = vec![ candidate(0, &[], false), PhysicalCandidate { - materialization: Materialization::MatAtQuery(Medium::Memory), + properties: PhysicalProperties::new( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ) + .unwrap(), ..candidate(1, &[&[0]], false) }, candidate(2, &[&[1]], true), @@ -907,11 +918,11 @@ fn kept_builds_match_fresh_builds_of(roots: Vec) -> MilpInputs { /// refresh window, (10 s, 0)); /// - 5: a KLL over `TimeRange(60 s)`, window (60 s, 0); /// - 8: a KLL over `TimeRange(10 s)` over `TimeShift(5 s)`, window -/// (10 s, 5 s), through two `NotMaterialized` ingestion-time nodes; +/// (10 s, 5 s), through two not-kept ingestion-time nodes; /// - 9: a KLL over the whole scan, an unbounded window. /// /// Candidates 0, 1, 4, 6 and 7 (the scan, ranges and shift) are -/// `NotMaterialized` at ingestion time; 10–14 are the query-time readers. +/// not kept, at ingestion time; 10–14 are the query-time readers. fn ingestion_views_of_three_windows_and_an_unbounded_one() -> PhysicalASAPMemoCandidates { use asap_types::ir::operator::{Reduction, Source, TimeShift}; use asap_types::ir::scalar::ColumnRef; @@ -989,12 +1000,15 @@ fn ingestion_views_of_three_windows_and_an_unbounded_one() -> PhysicalASAPMemoCa (views[4].clone(), 9), ]; let at_ingestion = |node: usize, producers: &[&[usize]], view: bool| PhysicalCandidate { - timing: ExecutionTiming::IngestionTime, - materialization: if view { - Materialization::MatAtIngestion(Medium::Memory) - } else { - Materialization::NotMaterialized - }, + properties: PhysicalProperties::new( + ExecutionTiming::IngestionTime, + if view { + Lifetime::AcrossEvaluations(Medium::Memory) + } else { + Lifetime::None + }, + ) + .unwrap(), ..candidate(node, producers, false) }; let mut candidates = vec![ @@ -1021,7 +1035,7 @@ fn ingestion_views_of_three_windows_and_an_unbounded_one() -> PhysicalASAPMemoCa // One `I_r` per refresh window: the two views over `TimeRange(10 s)` share // one; the 60 s view and the shifted 10 s view (window (10 s, 5 s), through -// a `NotMaterialized` shift and range) have their own; the unbounded view +// a not-kept shift and range) have their own; the unbounded view // gets an `Alone` one. Each `I_r` holds the scan and the stateless nodes // below its views, and each view's context reads across into its `I_r`. #[test] diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index 77100f7df..04e3af388 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -38,28 +38,28 @@ //! computation is multiplied by how often it is computed per second //! ([`NodeCost::cost_per_second`](asap_cost::NodeCost::cost_per_second)): //! -//! * A `NotMaterialized` node is recomputed for each consumer that reads it +//! * A not-kept node is recomputed for each consumer that reads it //! and is not stored: it is charged once per consumer //! ([`NodeCost::multiplier`](asap_cost::NodeCost::multiplier)) at the sum of their rates. Its consumers are //! the queries whose sub-DAG reaches it and the materialized nodes above //! it, counted without looking through a materialized node: a node below -//! one is computed when that node is. The `MatAtIngestion` consumers of +//! one is computed when that node is. The consumers kept at ingestion time of //! one refresh window (`PhysicalASAPDAG::refresh_window`: for a tumbling window //! chain, its tumbling-window width) are refreshed in one ingestion run and count as //! one consumer: a `Scan` under a KLL chain and a DDSketch chain of 10 s //! tumbling windows is computed once per second of arriving data, under chains of //! 10 s and 60 s tumbling windows twice. Stage 2 keeps a shared node one //! node (it copies it only for readers at two timings). A shared -//! `NotMaterialized` input costs what reading it separately does (#509 +//! not-kept input costs what reading it separately does (#509 //! Example 4) only when every consumer reads the same window: a query-time `Scan` is priced over the longest window //! read above it, so each consumer pays for that window, and a scan a 1 m //! and a 5 m window share costs more than two separate scans. Stage 2 -//! offers the highest shared node built once per evaluation (`MatAtQuery`) +//! offers the highest shared node built once per evaluation (`OneEvaluation`) //! as another candidate. -//! * A `MatAtQuery` node is computed once for all the queries that reach +//! * A `OneEvaluation` node is computed once for all the queries that reach //! it, at their combined rate: queries repeating at the same interval are //! evaluated together, so each distinct interval counts once. -//! * A `MatAtIngestion` node runs as data arrives: it is priced over one +//! * A node kept at ingestion time runs as data arrives: it is priced over one //! second of arriving rows, once per second, whatever its readers' rates. //! A tumbling-window chain maintained this way updates only its newest //! tumbling window: each arriving row is placed in it and updates it. @@ -70,20 +70,20 @@ //! //! Under cost model 1, memory is charged as bytes held per second //! ([`ResourceUsage::average_memory_bytes`](asap_cost::ResourceUsage::average_memory_bytes)), at -//! `cost_per_memory_byte_second` per byte per second. A `MatAtIngestion` +//! `cost_per_memory_byte_second` per byte per second. A node kept at ingestion time //! node keeps its state every second: twice for a whole window (the window //! being built and the completed one queries read) and `N + 1` tumbling windows for a //! chain of `N` (the `N` the query merges and the one being built). A -//! `MatAtQuery` node's state is reused only within one evaluation, so it is +//! `OneEvaluation` node's state is reused only within one evaluation, so it is //! held only while that evaluation runs: its bytes times the latency of the //! longest query reading it, once per evaluation. A query-time -//! `NotMaterialized` node's working memory (a sketch being built, an exact +//! not-kept node's working memory (a sketch being built, an exact //! aggregate's values) is charged once per consumer that recomputes it: //! for a query, its bytes times that query's latency, at its rate; for a //! materialized node reading it (directly or through other -//! `NotMaterialized` nodes), its bytes times the latency of the longest -//! query reading that node, at the node's rate, as a `MatAtQuery` state is. -//! A `MatAtQueryKeptAcrossEvaluations` tumbling-window chain (#509 Example +//! not-kept nodes), its bytes times the latency of the longest +//! query reading that node, at the node's rate, as a `OneEvaluation` state is. +//! A query-time `AcrossEvaluations` tumbling-window chain (#509 Example //! 4's B3, offered by Stage 2 when the deployment keeps query-time results, //! `DeploymentCapabilities::query_time_results_retained`) is kept across //! evaluations: each evaluation scans one tumbling window of raw data and builds the @@ -99,8 +99,8 @@ //! at 1 min steps): //! //! * every query-time computation that is not kept across evaluations -//! (`NotMaterialized`, `MatAtQuery`) runs once per step, `S` times per -//! request; a `MatAtIngestion` state is maintained as before, and the +//! (not kept, `OneEvaluation`) runs once per step, `S` times per +//! request; a kept at ingestion time state is maintained as before, and the //! merge and estimate over it run once per step; //! * a chain kept across evaluations is built once per request: Stage 2 //! offers it only when the requests repeat at its tumbling-window width, so in the @@ -116,7 +116,7 @@ //! `S = 1` and the retention is the window, so every price is as above. //! Memory a computation holds only while it runs counts in //! [`ResourceUsage::peak_memory_bytes`](asap_cost::ResourceUsage::peak_memory_bytes), which cost models 2 and 3 read, and -//! under cost model 1 for the time it is held, as above. (A `NotMaterialized` +//! under cost model 1 for the time it is held, as above. (A not-kept //! node computed at ingestion time is a streaming operator holding one row, //! and is not charged.) //! @@ -350,7 +350,7 @@ mod tests { }; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode, QueryRoot}; use asap_types::physical::PhysicalWorkloadPlan; - use asap_types::physical::{Materialization, Medium}; + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::workload::bounds::with_confirmed_weights; use asap_types::workload::bounds::{declared_series, series_read, values_per_result}; use asap_types::workload::{ @@ -1116,8 +1116,8 @@ mod tests { } /// Query 1 is `sum(...)` over query 2's output. Every node reached by - /// both queries is `NotMaterialized`, so recomputed for each: charged - /// twice. Materializing query 2's root (`MatAtQuery`) charges it once, + /// both queries is not kept, so recomputed for each: charged + /// twice. Materializing query 2's root (`OneEvaluation`) charges it once, /// and the nodes below it once, since they run only when it does. #[test] fn not_materialized_shared_nodes_are_charged_per_query() { @@ -1158,7 +1158,7 @@ mod tests { .iter_mut() .find(|n| n.id == inner) .unwrap(); - node.materialization = Materialization::MatAtQuery(asap_types::physical::Medium::Memory); + node.lifetime = Lifetime::OneEvaluation(Medium::Memory); let stored = price(&candidate.dag, &recurrences(2), &data(), &settings).unwrap(); for (id, c) in &stored.per_node { assert_eq!(c.multiplier, 1, "node {id} is computed once"); @@ -1171,7 +1171,7 @@ mod tests { assert!(stored.cost_per_second.unwrap() < cost.cost_per_second.unwrap()); } - /// A `NotMaterialized` node two queries read is computed for each, so + /// A not-kept node two queries read is computed for each, so /// its working memory is held once per query, each time for that /// query's latency: `bytes · Σ rate_q · latency_q`, not the longest /// latency at both rates. Query 1 is `sum(...)` over query 2's output, @@ -2424,9 +2424,9 @@ mod tests { } /// `candidates` with every state node (a summary build or an exact - /// aggregate) kept at ingestion time, so selection charges its kept - /// bytes every second (a `MatAtQuery` state is held only for one - /// evaluation). + /// aggregate) kept across evaluations, so selection charges its kept + /// bytes every second (a state kept for one evaluation is held only for + /// that evaluation). fn keeping_state(mut candidates: Vec) -> Vec { for candidate in &mut candidates { for node in &mut candidate.dag.nodes { @@ -2435,8 +2435,7 @@ mod tests { Payload::ASAP(ASAPOp::SummaryAgg { .. }) | Payload::NonASAP(NonASAPOp::Aggregate { .. }) ) { - node.materialization = - Materialization::MatAtIngestion(asap_types::physical::Medium::Memory); + node.lifetime = Lifetime::AcrossEvaluations(Medium::Memory); } } } @@ -3421,8 +3420,8 @@ mod tests { } /// `quantile_over_time(0.99, m[1m])` with its KLL candidate chosen, its - /// state materialized as `materialization`. - fn kll_dag(materialization: Materialization) -> PhysicalASAPDAG { + /// state kept with `kept` (`None`: not kept). + fn kll_dag(kept: Option) -> PhysicalASAPDAG { use asap_types::ir::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, }; @@ -3462,9 +3461,8 @@ mod tests { .into_iter() .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryAgg { .. }))) .expect("a KLL state"); - let mut assignment = - MaterializationAssignment::with_default(Materialization::NotMaterialized); - assignment.set(&state, materialization); + let mut assignment = MaterializationAssignment::default(); + assignment.set(&state, kept); let timed = apply_materialization_timings(root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -3528,10 +3526,26 @@ mod tests { assert!(range.detail.contains("keep"), "{}", range.detail); } - const AT_INGESTION: Materialization = - Materialization::MatAtIngestion(asap_types::physical::Medium::Memory); - const AT_QUERY: Materialization = - Materialization::MatAtQuery(asap_types::physical::Medium::Memory); + /// Kept `lifetime` at `timing`. + fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> Option { + Some(PhysicalProperties::new(timing, lifetime).unwrap()) + } + + /// Kept in memory at ingestion time until a query reads it. + fn at_ingestion() -> Option { + kept( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + } + + /// Kept in memory at query time for one evaluation. + fn at_query() -> Option { + kept( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ) + } fn node_of(dag: &PhysicalASAPDAG, pick: impl Fn(&Payload) -> bool) -> PhysicalASAPNodeId { dag.nodes.iter().find(|n| pick(&n.payload)).unwrap().id @@ -3568,7 +3582,7 @@ mod tests { /// node scales with that rate. #[test] fn ingestion_time_node_is_priced_per_second_of_arriving_rows() { - let dag = kll_dag(AT_INGESTION); + let dag = kll_dag(at_ingestion()); let (fast, slow) = ( priced(&dag, &[repeating(1_000)]), priced(&dag, &[repeating(10_000)]), @@ -3592,7 +3606,7 @@ mod tests { /// every second. At query time the state is reused only within one /// evaluation, so it is held only while that evaluation runs: its bytes /// times the evaluation's latency, once per evaluation. State computed - /// and dropped within a query (`NotMaterialized`) is held while that + /// and dropped within a query (not kept) is held while that /// query runs too, and charged the same way. #[test] fn kept_state_is_charged_per_byte_per_second() { @@ -3600,7 +3614,7 @@ mod tests { let settings = unit_costs(|c| c.cost_per_memory_byte_second = w); price(dag, &recurrences(1), &data(), &settings).unwrap() }; - for materialization in [AT_INGESTION, AT_QUERY, Materialization::NotMaterialized] { + for materialization in [at_ingestion(), at_query(), None] { let dag = kll_dag(materialization); let build = node_of(&dag, is_build); let (with, without) = (cost(&dag, 1.25e-7), cost(&dag, 0.0)); @@ -3613,15 +3627,16 @@ mod tests { // each sees its series' 12 samples: the 120 000 rows of its // source's 1-min window (data()'s 10 000 rows per second over its // five sources); at ingestion time its samples are unknown. - let samples = match materialization { - AT_INGESTION => StateInputRows::UNKNOWN, - _ => StateInputRows { + let samples = if materialization == at_ingestion() { + StateInputRows::UNKNOWN + } else { + StateInputRows { rows_per_state: Some(12), non_negative: false, - }, + } }; let state = 10_000.0 * summary_shape(family, samples).1 as f64; - let byte_seconds = if materialization == AT_INGESTION { + let byte_seconds = if materialization == at_ingestion() { 2.0 * state } else { let evaluation_s = with.usage.latency_per_query[0].total_ms() / 1_000.0; @@ -3680,7 +3695,7 @@ mod tests { (query.to_string(), dag) }) .collect(); - for materialization in [AT_INGESTION, AT_QUERY, Materialization::NotMaterialized] { + for materialization in [at_ingestion(), at_query(), None] { dags.push((format!("{materialization:?}"), kll_dag(materialization))); } for (name, dag) in &dags { @@ -3697,7 +3712,7 @@ mod tests { } // Not materialized, nothing is kept, but the sketch being built is // held while the query runs: the memory price adds to the cost. - let (term, _) = memory_term(&kll_dag(Materialization::NotMaterialized)); + let (term, _) = memory_term(&kll_dag(None)); assert!(term > 0.0, "{term}"); } @@ -3718,7 +3733,7 @@ mod tests { .iter_mut() .find(|n| matches!(n.payload, Payload::NonASAP(NonASAPOp::Aggregate { .. }))) .unwrap(); - aggregate.materialization = AT_QUERY; + aggregate.lifetime = Lifetime::OneEvaluation(Medium::Memory); let id = aggregate.id; let cost = |w| { let settings = unit_costs(|c| c.cost_per_memory_byte_second = w); @@ -3741,8 +3756,8 @@ mod tests { assert!(quantile > 10 * sum, "{quantile} vs {sum}"); } - /// A `NotMaterialized` node read by two queries is computed for each, at - /// each one's rate; `MatAtQuery`, it is computed once at their combined + /// A not-kept node read by two queries is computed for each, at + /// each one's rate; `OneEvaluation`, it is computed once at their combined /// rate, where queries at the same interval run together. #[test] fn rates_follow_per_consumer_charging() { @@ -3780,7 +3795,7 @@ mod tests { assert!(close(total(&two, &mixed), 1.5 * single)); assert_eq!(two.roots[0], two.roots[1], "one root node for both queries"); for node in &mut two.nodes { - node.materialization = AT_QUERY; + node.lifetime = Lifetime::OneEvaluation(Medium::Memory); } assert!(close(total(&two, &recurrences(2)), single)); assert!(close(total(&two, &mixed), 1.5 * single)); @@ -4044,11 +4059,11 @@ mod tests { /// evaluations, and only that. Without it, Stage 2 offers the 1-min /// tumbling windows of a query repeating every minute rebuilt (B2) or maintained /// (B1); with it, also built at query time and kept (B3, - /// `MatAtQueryKeptAcrossEvaluations`). B3 is computed once per + /// query-time `AcrossEvaluations`). B3 is computed once per /// evaluation, reads one tumbling window (1 min) of raw data, keeps that much raw /// data on disk, and holds its 4 older tumbling windows in memory between /// evaluations (on disk, if it were placed there). The same chain - /// `MatAtQuery` is reused only within one evaluation: the scan reads the + /// `OneEvaluation` is reused only within one evaluation: the scan reads the /// 5-min window and nothing is kept between evaluations. #[test] fn query_time_results_retained_keeps_a_tumbling_window_chain_across_evaluations() { @@ -4058,19 +4073,14 @@ mod tests { let b2 = &candidates[0].dag; let b3 = &candidates[2].dag; let chain = node_of(b3, is_chain); - let with_chain = |materialization: Materialization| { + let with_chain = |lifetime: Lifetime| { let mut dag = b3.clone(); for node in dag.nodes.iter_mut().filter(|n| n.id == chain) { - node.materialization = materialization; + node.lifetime = lifetime; } dag }; - assert_eq!( - *b3, - with_chain(Materialization::MatAtQueryKeptAcrossEvaluations( - Medium::Memory - )) - ); + assert_eq!(*b3, with_chain(Lifetime::AcrossEvaluations(Medium::Memory))); let recurrence = [repeating(MINUTE)]; let settings = CostInputs::default(); let kept = price(b3, &recurrence, &arriving(10_000.0), &settings).unwrap(); @@ -4102,9 +4112,7 @@ mod tests { .detail .contains(&format!("keeps {between} bytes across evaluations"))); // On disk, the same N − 1 older tumbling windows are kept. - let on_disk = with_chain(Materialization::MatAtQueryKeptAcrossEvaluations( - Medium::Disk, - )); + let on_disk = with_chain(Lifetime::AcrossEvaluations(Medium::Disk)); let on_disk = price(&on_disk, &recurrence, &arriving(10_000.0), &settings).unwrap(); assert_eq!( on_disk.usage.disk_bytes, @@ -4112,7 +4120,7 @@ mod tests { "{on_disk:?}" ); // Shared within one evaluation, nothing is kept between them. - let shared = with_chain(Materialization::MatAtQuery(Medium::Memory)); + let shared = with_chain(Lifetime::OneEvaluation(Medium::Memory)); let within_one = price(&shared, &recurrence, &arriving(10_000.0), &settings).unwrap(); assert_eq!(scanned_samples(&within_one, scan), 10_000 * 300); assert!(!within_one.per_node[&chain] @@ -4640,13 +4648,24 @@ mod tests { /// disk, nothing to average memory, and costs only its disk price. #[test] fn state_on_disk_is_counted_as_disk_not_memory() { - use asap_types::physical::Medium; let settings = unit_costs(|c| c.cost_per_disk_byte_second = 1e-9); let work_only = unit_costs(|c| c.cost_per_memory_byte_second = 0.0); let state = |dag: &PhysicalASAPDAG| node_of(dag, is_build); for (on_disk, in_memory) in [ - (Materialization::MatAtIngestion(Medium::Disk), AT_INGESTION), - (Materialization::MatAtQuery(Medium::Disk), AT_QUERY), + ( + kept( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Disk), + ), + at_ingestion(), + ), + ( + kept( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Disk), + ), + at_query(), + ), ] { let (disk_dag, memory_dag) = (kll_dag(on_disk), kll_dag(in_memory)); let disk = price(&disk_dag, &recurrences(1), &data(), &settings).unwrap(); @@ -4812,9 +4831,9 @@ mod tests { .find(|c| { c.dag.nodes.iter().all(|n| match n.payload { Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) => { - matches!(n.materialization, Materialization::MatAtIngestion(_)) + n.output_state.timing == ExecutionTiming::IngestionTime && n.lifetime.is_kept() } - _ => n.materialization == Materialization::NotMaterialized, + _ => n.lifetime == Lifetime::None, }) }) .unwrap() diff --git a/crates/plan-selection/src/milp/cost_terms.rs b/crates/plan-selection/src/milp/cost_terms.rs index 7814f7b3c..589a60bfd 100644 --- a/crates/plan-selection/src/milp/cost_terms.rs +++ b/crates/plan-selection/src/milp/cost_terms.rs @@ -34,7 +34,7 @@ //! //! **Held memory**: working memory of a run in query context `q` for `q`'s //! latency at `q`'s rate (`H_query ≥ L[q] − L̄[q] (1 − indicator)`); `m`'s -//! `MatAtQuery(Memory)` result and the working memory of the runs in its +//! `OneEvaluation(Memory)` result and the working memory of the runs in its //! context until `m`'s slowest reader finishes (`H[m] ≥ L[q] − L̄[q] (1 − //! a[q, m])`, then `W ≥ H[m] − H̄[m] (slack − Σ indicators)` per rate //! component). @@ -57,7 +57,7 @@ use asap_cost::CostModel; use asap_types::ir::physical_export::ScanWindow; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{NonASAPOp, Operator}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium}; use asap_types::stages::PhysicalCandidateId; use asap_types::workload::bounds::source_name; use asap_types::workload::{QueryRecurrence, RepeatedDemand}; @@ -693,7 +693,8 @@ fn pane_retention_terms( let mut indicators = Vec::new(); if let Some(&reach) = milp.reach.get(&(query, chain)) { if at_query_time - || milp.physical.candidates[chain.0].timing == ExecutionTiming::QueryTime + || milp.physical.candidates[chain.0].properties.timing() + == ExecutionTiming::QueryTime { indicators.push(Expression::from(reach)); reached.push((query, indicators)); @@ -776,7 +777,9 @@ pub(crate) fn compaction_ms(milp: &mut SelectionMilp<'_>) -> HashMap ContextRate::Fixed(query_rate[query]), ContextKind::Ingestion(_) => ContextRate::Fixed(1.0), ContextKind::Shared(m) => { - let per_request = match milp.physical.candidates[m.0].materialization { - Materialization::MatAtIngestion(_) | Materialization::NotMaterialized => { + let properties = milp.physical.candidates[m.0].properties; + let per_request = match (properties.timing(), properties.lifetime()) { + (ExecutionTiming::IngestionTime, _) | (_, Lifetime::None) => { rates.push(ContextRate::Fixed(1.0)); continue; } - Materialization::MatAtQuery(_) => false, - Materialization::MatAtQueryKeptAcrossEvaluations(_) => true, + (ExecutionTiming::QueryTime, Lifetime::OneEvaluation(_)) => false, + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => true, }; let readers = milp.queries_reaching(m); let demand = |query: usize| { @@ -988,7 +992,10 @@ pub(crate) fn encode_objective(milp: &mut SelectionMilp<'_>) -> Result<(), Selec let terms = milp.run_terms(context, candidate); milp.builder.scope = milp.scope_of(context); let candidate_data = &milp.physical.candidates[candidate.0]; - let (timing, materialization) = (candidate_data.timing, candidate_data.materialization); + let (timing, lifetime) = ( + candidate_data.properties.timing(), + candidate_data.properties.lifetime(), + ); let own = milp.inputs.contexts[context].kind == ContextKind::Shared(candidate); // The most this run adds to its context's execution cost: all its // terms at 1. @@ -1034,7 +1041,7 @@ pub(crate) fn encode_objective(milp: &mut SelectionMilp<'_>) -> Result<(), Selec charge(&held.into(), per_byte_ms * query_rate[query]); } ContextKind::Shared(m) => { - if own && materialization != Materialization::MatAtQuery(Medium::Memory) { + if own && lifetime != Lifetime::OneEvaluation(Medium::Memory) { milp.note_inexact("held bytes of a shareable candidate not in memory"); } let (longest, most_held) = *held_time.entry(context).or_insert_with(|| { @@ -1166,7 +1173,7 @@ fn raw_retention( else { continue; }; - if milp.physical.candidates[candidate.0].timing != ExecutionTiming::QueryTime { + if milp.physical.candidates[candidate.0].properties.timing() != ExecutionTiming::QueryTime { continue; } let source = source_name(source).to_string(); diff --git a/crates/plan-selection/src/milp/decode.rs b/crates/plan-selection/src/milp/decode.rs index 5b8b53466..1b9ba8216 100644 --- a/crates/plan-selection/src/milp/decode.rs +++ b/crates/plan-selection/src/milp/decode.rs @@ -1,9 +1,9 @@ //! #1095 Step 6 (§2.0, "Decode and check"): the group selection MILP's raw //! solution as a [`DagOfSelectedCandidates`], one node per candidate run. //! -//! - A candidate computed in a context (`p[ctx, c] = 1`, a `NotMaterialized` +//! - A candidate computed in a context (`p[ctx, c] = 1`, a not-kept //! query-time candidate in a query's or a shareable candidate's context, -//! or a `NotMaterialized` ingestion-time candidate in an `I_r`) is one node per +//! or a not-kept ingestion-time candidate in an `I_r`) is one node per //! context: selected in two contexts, it is two nodes; read by two //! readers in one context, it is one. //! - A selected shareable candidate (`x[m] = 1`) is one node, whoever reads diff --git a/crates/plan-selection/src/milp/lp_diagnosis.rs b/crates/plan-selection/src/milp/lp_diagnosis.rs index d8bdc113f..5b0b6e5b0 100644 --- a/crates/plan-selection/src/milp/lp_diagnosis.rs +++ b/crates/plan-selection/src/milp/lp_diagnosis.rs @@ -178,8 +178,8 @@ impl Diagnosis { "c{} {} {:?} {:?}", c.0, milp.physical.physical_node(c).operator.kind_name(), - data.timing, - data.materialization + data.properties.timing(), + data.properties.lifetime() ) }; let mut labels = BTreeMap::new(); diff --git a/crates/plan-selection/src/milp/model/tests.rs b/crates/plan-selection/src/milp/model/tests.rs index a8ec9f4a0..f6bb31384 100644 --- a/crates/plan-selection/src/milp/model/tests.rs +++ b/crates/plan-selection/src/milp/model/tests.rs @@ -6,7 +6,7 @@ use crate::milp::decode::{decode, ChosenCandidates}; use asap_cost::{node_map, plan_cost, PlanCost, ResourceUnitCost}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{OperatorNode, QueryRoot}; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium}; use asap_types::stages::{AssignmentRealizer, DagOfSelectedCandidates, PhysicalCandidate}; use asap_types::workload::{DataWorkload, DurationMs, RangeEvaluation}; @@ -324,7 +324,7 @@ fn forbid(milp: &mut SelectionMilp<'_>, candidates: &[PhysicalCandidateId]) { /// The candidates that are pane chains or run at ingestion time. fn pane_chains_and_ingestion(milp: &SelectionMilp<'_>) -> Vec { candidates_where(milp, |candidate, node| { - candidate.timing == ExecutionTiming::IngestionTime + candidate.properties.timing() == ExecutionTiming::IngestionTime || matches!( node.asap(), Some(asap_types::ir::ASAPOp::SummaryTumblingWindowChain { .. }) @@ -372,7 +372,7 @@ fn the_optimum_costs_what_plan_cost_says() { } } -// Held memory and schedule groups: a `MatAtQuery(Memory)` result both +// Held memory and schedule groups: a `OneEvaluation(Memory)` result both // queries read (every 60 s and every 30 s) is held until the slower reader // finishes, once per execution at the schedule groups' rates. #[test] @@ -380,7 +380,7 @@ fn held_memory_of_a_result_readers_of_different_latency_share() { let fixture = shared_sum(); let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { let shared: Vec = candidates_where(milp, |candidate, _| { - candidate.materialization == Materialization::MatAtQuery(Medium::Memory) + candidate.properties.lifetime() == Lifetime::OneEvaluation(Medium::Memory) }) .into_iter() .filter(|&candidate| milp.queries_reaching(candidate).len() == 2) @@ -477,10 +477,8 @@ fn a_kept_pane_chain_keeps_the_longest_readers_span() { matches!( node.asap(), Some(asap_types::ir::ASAPOp::SummaryTumblingWindowChain { .. }) - ) && matches!( - candidate.materialization, - Materialization::MatAtIngestion(_) - ) + ) && (candidate.properties.timing() == ExecutionTiming::IngestionTime + && candidate.properties.lifetime().is_kept()) }); require_one_of(milp, &chains); }) @@ -496,7 +494,7 @@ fn a_kept_pane_chain_keeps_the_longest_readers_span() { ); } -// A `NotMaterialized` input of a `MatAtQuery` candidate both queries read +// A not-kept input of a `OneEvaluation` candidate both queries read // (`rate(m[5m])` under `sum` and `max`, one schedule group) runs once, in // the candidate's context, and is costed as `plan_cost` costs it. #[test] @@ -511,7 +509,7 @@ fn a_shared_results_not_materialized_input_runs_once() { let mut shared = Vec::new(); let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { shared = candidates_where(milp, |candidate, _| { - matches!(candidate.materialization, Materialization::MatAtQuery(_)) + matches!(candidate.properties.lifetime(), Lifetime::OneEvaluation(_)) }) .into_iter() .filter(|&m| milp.queries_reaching(m).len() == 2) @@ -565,8 +563,8 @@ fn one_ingestion_scan_shared_by_two_sketch_configurations_is_charged_once() { ); let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { let sketches = candidates_where(milp, |candidate, node| { - candidate.timing == ExecutionTiming::IngestionTime - && candidate.materialization != Materialization::NotMaterialized + candidate.properties.timing() == ExecutionTiming::IngestionTime + && candidate.properties.lifetime().is_kept() && matches!( node.asap(), Some(asap_types::ir::ASAPOp::SummaryAgg { .. }) @@ -581,7 +579,8 @@ fn one_ingestion_scan_shared_by_two_sketch_configurations_is_charged_once() { milp.builder.row("test", constraint!(sum >= 2.0)); // Every query-time scan is excluded: both read ingestion state. let scans = candidates_where(milp, |candidate, node| { - candidate.timing == ExecutionTiming::QueryTime && node.operator.kind_name() == "Scan" + candidate.properties.timing() == ExecutionTiming::QueryTime + && node.operator.kind_name() == "Scan" }); forbid(milp, &scans); }) @@ -589,7 +588,8 @@ fn one_ingestion_scan_shared_by_two_sketch_configurations_is_charged_once() { let ingestion_scans: Vec = (0..checked.dag.candidate_of_node.len()) .filter(|&node| { let candidate = checked.dag.candidate_of_node[node]; - fixture.physical.candidates[candidate.0].timing == ExecutionTiming::IngestionTime + fixture.physical.candidates[candidate.0].properties.timing() + == ExecutionTiming::IngestionTime && fixture .physical .physical_node(candidate) @@ -615,8 +615,8 @@ fn ingestion_scans_under_refresh_windows( let fixture = through_stages_with(queries, true, true); let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { let states = candidates_where(milp, |candidate, _| { - candidate.timing == ExecutionTiming::IngestionTime - && candidate.materialization != Materialization::NotMaterialized + candidate.properties.timing() == ExecutionTiming::IngestionTime + && candidate.properties.lifetime().is_kept() }); let window_of = |state: PhysicalCandidateId| { milp.inputs @@ -650,7 +650,8 @@ fn ingestion_scans_under_refresh_windows( .sum(); milp.builder.row("test", constraint!(sum >= 2.0)); let scans = candidates_where(milp, |candidate, node| { - candidate.timing == ExecutionTiming::QueryTime && node.operator.kind_name() == "Scan" + candidate.properties.timing() == ExecutionTiming::QueryTime + && node.operator.kind_name() == "Scan" }); forbid(milp, &scans); }) @@ -687,7 +688,8 @@ fn ingestion_scans_under_refresh_windows( let scans = (0..nodes) .filter(|&node| { let candidate = dag.candidate_of_node[node]; - fixture.physical.candidates[candidate.0].timing == ExecutionTiming::IngestionTime + fixture.physical.candidates[candidate.0].properties.timing() + == ExecutionTiming::IngestionTime && fixture .physical .physical_node(candidate) @@ -805,7 +807,7 @@ fn a_stateless_subtree_two_state_nodes_read_runs_once() { // "Used only if read": a query context may not select a shareable // candidate no used reader there reads, so a phantom read cannot satisfy -// `MinimumQueryReaders`. With every reader of a two-reader `MatAtQuery` +// `MinimumQueryReaders`. With every reader of a two-reader `OneEvaluation` // result in the second query's context forbidden, selecting it is // infeasible. #[test] @@ -860,7 +862,7 @@ fn a_phantom_reader_does_not_satisfy_minimum_query_readers() { ); } -// A `NotMaterialized` query-time candidate selected in two contexts is two +// A not-kept query-time candidate selected in two contexts is two // nodes; a shareable candidate two queries read is one node. #[test] fn runs_decode_one_node_per_context_and_one_per_shareable_candidate() { @@ -870,12 +872,12 @@ fn runs_decode_one_node_per_context_and_one_per_shareable_candidate() { ); let unshared = solve_and_check(&fixture, &cost_inputs(), |milp| { let shared = candidates_where(milp, |candidate, _| { - candidate.timing == ExecutionTiming::QueryTime - && candidate.materialization != Materialization::NotMaterialized + candidate.properties.timing() == ExecutionTiming::QueryTime + && candidate.properties.lifetime().is_kept() }); forbid(milp, &shared); let ingestion = candidates_where(milp, |candidate, _| { - candidate.timing == ExecutionTiming::IngestionTime + candidate.properties.timing() == ExecutionTiming::IngestionTime }); forbid(milp, &ingestion); }) @@ -888,7 +890,7 @@ fn runs_decode_one_node_per_context_and_one_per_shareable_candidate() { let mut shared_result = Vec::new(); let shared = solve_and_check(&fixture, &cost_inputs(), |milp| { shared_result = candidates_where(milp, |candidate, _| { - candidate.materialization == Materialization::MatAtQuery(Medium::Memory) + candidate.properties.lifetime() == Lifetime::OneEvaluation(Medium::Memory) }) .into_iter() .filter(|&m| milp.queries_reaching(m).len() == 2) diff --git a/crates/planner/src/installable.rs b/crates/planner/src/installable.rs index ea836d674..86592d37f 100644 --- a/crates/planner/src/installable.rs +++ b/crates/planner/src/installable.rs @@ -50,7 +50,7 @@ use crate::{e2e_plan, PlanError, UserInput}; /// The version of the plan-file format [`InstallablePlan`] serializes to: /// the DAG, its nodes' fields and the query texts. -pub const INSTALLABLE_PLAN_WIRE_VERSION: u32 = 11; +pub const INSTALLABLE_PLAN_WIRE_VERSION: u32 = 12; /// The selected plan, ready to install and execute: what /// [`plan_installable`] returns and a runtime writes as its plan file. @@ -791,9 +791,10 @@ fn report_of( #[cfg(test)] mod tests { use super::*; + use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{SketchAlgorithm, StatisticKind, SupportedSummary}; use asap_types::ir::{NonASAPOp, Operator}; - use asap_types::physical::Materialization; + use asap_types::physical::{Lifetime, PhysicalProperties}; thread_local! { /// The plan nodes handed to the executor's compiler by the views' @@ -999,7 +1000,14 @@ mod tests { })) .unwrap(); let mut assignment = MaterializationAssignment::default(); - assignment.set(&merged, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + &merged, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); let timed = apply_materialization_timings(&merged, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -1036,7 +1044,14 @@ mod tests { .unwrap(); let mut assignment = MaterializationAssignment::default(); for node in tumbling_windows.iter().chain([&merge]) { - assignment.set(node, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + node, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); } let timed = apply_materialization_timings(&merge, &assignment, &mut NodeToTimedNodeCache::new()) diff --git a/crates/planner/src/pass.rs b/crates/planner/src/pass.rs index 9d699cfc9..5ded2a5a8 100644 --- a/crates/planner/src/pass.rs +++ b/crates/planner/src/pass.rs @@ -299,7 +299,7 @@ impl PlanOutput { } /// The workload as one physical ASAP DAG, with shared sub-DAGs exported - /// once. A node keeps the timing and materialization its pass gave it: + /// once. A node keeps the timing and lifetime its pass gave it: /// for [`Stage1ToStage3Pass`] that is Stage 3's selected plan as /// selected (e.g. ingestion-time tumbling windows), the document a deployment /// runtime executes. Only a node the pass left untimed takes the default diff --git a/crates/planner/tests/deployment_accuracy_model.rs b/crates/planner/tests/deployment_accuracy_model.rs index 91cda2b04..6267590ec 100644 --- a/crates/planner/tests/deployment_accuracy_model.rs +++ b/crates/planner/tests/deployment_accuracy_model.rs @@ -90,7 +90,6 @@ fn physical_candidates( compose_logical_candidate, generate_per_computation_candidates, }; use asap_physical_asap_optimization::test_support::optimize_physical_asap_chosen; - use asap_types::physical::Materialization; let roots = lower_promql_query_workload(workload).expect("lowers"); let inventory = generate_per_computation_candidates( @@ -116,7 +115,7 @@ fn physical_candidates( &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(Materialization::NotMaterialized), + &mut |_, _, _| Some(None), ) .unwrap() .expect("query-time fixture is executable"); diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index 7b952acb2..998016695 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -25,13 +25,14 @@ use asap_planner::{ SelectionBox, Stage1ToStage3Pass, UserInput, }; use asap_types::ir::operator::Source; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::schema_support::with_promql_series_identity; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm, SketchParams}; use asap_types::ir::{ apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, OperatorNode, QueryRoot, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::stages::HowToComputeAggregateMeasure; use asap_types::stages::PruneReason; use futures::{executor::block_on, StreamExt}; @@ -1516,7 +1517,7 @@ async fn a_quantile_shared_with_a_ratio_is_sized_for_the_ratio() { /// the others as Stage 2 chose, and the plan timed again: how a test makes /// the plan store a shape Stage 3 does not select today. struct StoredAsForced { - store: fn(&OperatorNode) -> Option, + store: fn(&OperatorNode) -> Option, } impl OptimizationPass for StoredAsForced { @@ -1550,11 +1551,11 @@ impl OptimizationPass for StoredAsForced { } } -/// `node` untimed, with `store`'s materialization (or its own) recorded in +/// `node` untimed, with `store`'s kept output (or its own) recorded in /// `assignment` for every node of its sub-DAG. fn untime( node: &Rc, - store: fn(&OperatorNode) -> Option, + store: fn(&OperatorNode) -> Option, untimed: &mut HashMap<*const OperatorNode, Rc>, assignment: &mut MaterializationAssignment, ) -> Rc { @@ -1566,7 +1567,7 @@ fn untime( .operator .map_children(|child| untime(child, store, untimed, assignment)); copy.timing = None; - copy.materialization = Materialization::NotMaterialized; + copy.lifetime = Lifetime::None; let copy = Rc::new(copy); // A shared non-summary node Stage 2 built once per evaluation is not // kept: a build forced to ingestion time above it cannot read a @@ -1576,28 +1577,39 @@ fn untime( ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } | ASAPOp::SummaryMerge { .. }, - ) => node.materialization, - _ => Materialization::NotMaterialized, + ) if node.lifetime.is_kept() => Some( + PhysicalProperties::new(node.timing.expect("a timed plan"), node.lifetime).unwrap(), + ), + _ => None, }; - let materialization = store(node).unwrap_or(own); - if materialization != Materialization::NotMaterialized { - assignment.set(©, materialization); + let kept = store(node).or(own); + if kept.is_some() { + assignment.set(©, kept); } untimed.insert(Rc::as_ptr(node), Rc::clone(©)); copy } /// Every `SummaryAgg` built at ingestion time. -fn summaries_at_ingestion(node: &OperatorNode) -> Option { - matches!(node.asap(), Some(ASAPOp::SummaryAgg { .. })) - .then_some(Materialization::MatAtIngestion(Medium::Memory)) +fn summaries_at_ingestion(node: &OperatorNode) -> Option { + matches!(node.asap(), Some(ASAPOp::SummaryAgg { .. })).then(|| { + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .unwrap() + }) } /// Every `SummaryMerge` built at query time and kept across evaluations. -fn merges_kept(node: &OperatorNode) -> Option { - matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })).then_some( - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), - ) +fn merges_kept(node: &OperatorNode) -> Option { + matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })).then(|| { + PhysicalProperties::new( + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .unwrap() + }) } /// Exact PromQL `queries`, every minute, over 6 ingesting series of `m` @@ -1628,7 +1640,7 @@ fn exact_workload(queries: &[&str], tail: &str) -> PlanningWorkload { async fn forced_plan_json( workload: &PlanningWorkload, capabilities: &DeploymentCapabilities, - store: fn(&OperatorNode) -> Option, + store: fn(&OperatorNode) -> Option, ) -> String { let pass = StoredAsForced { store }; let mut input = UserInput::new( diff --git a/crates/planner/tests/summary_sharing.rs b/crates/planner/tests/summary_sharing.rs index bc7658d28..65e8a3629 100644 --- a/crates/planner/tests/summary_sharing.rs +++ b/crates/planner/tests/summary_sharing.rs @@ -142,7 +142,7 @@ fn composed_summary_candidates( &entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(asap_types::physical::Materialization::NotMaterialized), + &mut |_, _, _| Some(None), ) .unwrap() .expect("supported physical computation"); @@ -161,7 +161,6 @@ fn shared_kll_candidate(workload: &PlanningWorkload) -> asap_types::physical::Ph use asap_logical_asap_optimization::test_support::{ compose_logical_candidate, generate_per_computation_candidates, }; - use asap_types::physical::Materialization; let roots = lower_promql_query_workload(workload).unwrap(); let inventory = generate_per_computation_candidates( &asap_logical_asap_optimization::generate_dag_of_logical_memo_groups(&roots), @@ -201,7 +200,7 @@ fn shared_kll_candidate(workload: &PlanningWorkload) -> asap_types::physical::Ph &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(Materialization::NotMaterialized), + &mut |_, _, _| Some(None), ) .unwrap() .unwrap(); diff --git a/crates/types/src/ir/flat.rs b/crates/types/src/ir/flat.rs index ac56e5b5f..9926e0632 100644 --- a/crates/types/src/ir/flat.rs +++ b/crates/types/src/ir/flat.rs @@ -18,7 +18,7 @@ use crate::ir::operator::query::QueryRoot; use crate::ir::properties::execution_data_state::ExecutionTiming; use crate::ir::properties::guarantee::AccuracyGuarantee; use crate::ir::schema::Schema; -use crate::physical::materialization::Materialization; +use crate::physical::Lifetime; /// Index of a node in [`FlatDag::nodes`]. pub type NodeId = usize; @@ -31,7 +31,7 @@ pub struct FlatNode { pub(crate) schema: Schema, pub(crate) guarantee: Option, pub(crate) timing: Option, - pub(crate) materialization: Materialization, + pub(crate) lifetime: Lifetime, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -79,7 +79,7 @@ fn visit( schema: node.schema.clone(), guarantee: node.guarantee.clone(), timing: node.timing, - materialization: node.materialization, + lifetime: node.lifetime, }); originals.push(Rc::clone(node)); ids.insert(Rc::as_ptr(node), id); diff --git a/crates/types/src/ir/materialized_view.rs b/crates/types/src/ir/materialized_view.rs index 6a3c2de29..10262e043 100644 --- a/crates/types/src/ir/materialized_view.rs +++ b/crates/types/src/ir/materialized_view.rs @@ -6,9 +6,9 @@ //! ([`PhysicalASAPDAG::set_retention`]). //! //! A **materialized view** is a node whose output is kept across -//! evaluations: its materialization is `MatAtIngestion` or -//! `MatAtQueryKeptAcrossEvaluations`, and it carries its `retention_ms`. A -//! `MatAtQuery` node is not a view: its output is discarded after one +//! evaluations: its lifetime is `AcrossEvaluations`, at ingestion time or +//! at query time, and it carries its `retention_ms`. A node kept for +//! `OneEvaluation` is not a view: its output is discarded after one //! evaluation. A query-time `Scan` carries how long its source's rows are //! kept for it (`None` when it reads them unbounded). //! @@ -79,7 +79,7 @@ use crate::ir::operator::non_asap::NonASAPOp; use crate::ir::operator::operator_properties::Source; use crate::ir::properties::execution_data_state::ExecutionTiming; use crate::ir::properties::summary_coverage::{CoverageError, SelectionBox, SummaryCoverage}; -use crate::physical::materialization::Materialization; +use crate::physical::Lifetime; /// One materialized view of a DAG: what its stored state is, what it is /// refreshed from, when, and for how long it is kept. @@ -235,13 +235,13 @@ impl RawDataWindow { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum MaterializedViewRefresh { - /// Refreshed at ingestion time (`MatAtIngestion`): the runtime runs the + /// Refreshed at ingestion time (kept at ingestion time): the runtime runs the /// node in an ingestion run once its inputs are complete (its windows' /// samples have arrived and the views it reads are refreshed), and /// keeps the result. AtIngestion, /// Refreshed at query time and kept across evaluations - /// (`MatAtQueryKeptAcrossEvaluations`): when an evaluation reads this + /// (query-time `AcrossEvaluations`): when an evaluation reads this /// view for a selection it has not been refreshed for yet, the runtime /// runs the node in a query run over its inputs, keeps the result, and /// binds it like a view refreshed at ingestion. @@ -401,7 +401,7 @@ impl PhysicalASAPDAG { if let Some(node) = self .nodes .iter() - .find(|node| node.materialization.is_materialized_view() && node.retention_ms.is_none()) + .find(|node| is_view(node) && node.retention_ms.is_none()) { return Err(InstallableDagError::ViewWithoutRetention { node_id: node.id }); } @@ -730,7 +730,7 @@ impl PhysicalASAPDAG { let views: HashSet = self .nodes .iter() - .filter(|node| node.materialization.is_materialized_view()) + .filter(|node| is_view(node)) .map(|node| node.id) .collect(); // The IR of each node, which coverage is derived from. @@ -764,7 +764,8 @@ impl PhysicalASAPDAG { { window_by_view.insert(id, window); } - if matches!(node.materialization, Materialization::MatAtIngestion(_)) { + let refreshed_at_ingestion = node.output_state.timing == ExecutionTiming::IngestionTime; + if refreshed_at_ingestion { // An ingestion run reads each view for the window ending at // its end, so a view read must end where the raw windows do. let mut end_offsets_ms: Vec = inputs @@ -796,9 +797,10 @@ impl PhysicalASAPDAG { coverage_by_node.insert(id, coverage.clone()); let view = MaterializedView { node_id: id, - refresh: match node.materialization { - Materialization::MatAtIngestion(_) => MaterializedViewRefresh::AtIngestion, - _ => MaterializedViewRefresh::OnFirstRead, + refresh: if refreshed_at_ingestion { + MaterializedViewRefresh::AtIngestion + } else { + MaterializedViewRefresh::OnFirstRead }, coverage: ViewCoverage { definition_id: coverage.definition_id(), @@ -1159,3 +1161,9 @@ fn with_replaced( } replace(node, old, new, &mut HashMap::new()) } + +/// Whether `node` is a materialized view: its output is kept across +/// evaluations. +fn is_view(node: &PhysicalASAPDAGNode) -> bool { + matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) +} diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index d2ae4f643..1d691fa7f 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -15,7 +15,7 @@ use crate::ir::properties::guarantee::AccuracyGuarantee; use crate::ir::properties::summary_coverage::{NodeToSummaryCoverageCache, SummaryCoverage}; use crate::ir::schema::Schema; use crate::ir::SchemaDerivationError; -use crate::physical::materialization::Materialization; +use crate::physical::Lifetime; /// The output category of an operator, derived from the operation and its /// inputs. Matching column schemas do not make categories interchangeable. @@ -93,9 +93,9 @@ impl Operator { /// at construction and retained. `guarantee` is `None` until accuracy /// assessment establishes one (`None` never means exact). `timing` is `None` /// until a materialization assignment is applied; export rejects an executable -/// node without one. `materialization` is the option that assignment chose -/// for this node (`NotMaterialized` until then, and for every node whose -/// output is not stored). +/// node without one. `lifetime` is how long that assignment keeps this +/// node's output (`None` until then, and for every node whose output is not +/// kept); with `timing` it is the node's [`crate::physical::PhysicalProperties`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct OperatorNode { pub operator: Operator, @@ -103,7 +103,7 @@ pub struct OperatorNode { pub schema: Schema, pub guarantee: Option, pub timing: Option, - pub materialization: Materialization, + pub lifetime: Lifetime, } impl OperatorNode { @@ -128,7 +128,7 @@ impl OperatorNode { schema, guarantee: None, timing: None, - materialization: Materialization::NotMaterialized, + lifetime: Lifetime::None, } } @@ -149,8 +149,8 @@ impl OperatorNode { self } - pub fn with_materialization(mut self, materialization: Materialization) -> Self { - self.materialization = materialization; + pub fn with_lifetime(mut self, lifetime: Lifetime) -> Self { + self.lifetime = lifetime; self } @@ -237,7 +237,7 @@ impl OperatorNode { /// the old derived schema are retained, for either operator category. A /// change in output arity with such overrides needs an explicit new /// naming assignment. - /// `guarantee`, `timing` and `materialization` depend on the inputs and + /// `guarantee`, `timing` and `lifetime` depend on the inputs and /// are cleared. pub fn with_new_children( &self, diff --git a/crates/types/src/ir/operator/tumbling_window_chain.rs b/crates/types/src/ir/operator/tumbling_window_chain.rs index 8416fa701..8a97e40cc 100644 --- a/crates/types/src/ir/operator/tumbling_window_chain.rs +++ b/crates/types/src/ir/operator/tumbling_window_chain.rs @@ -228,8 +228,8 @@ fn build_over( /// reads each tumbling window of each chain it read, newest first, as plain /// `SummaryAgg` nodes the executor runs; a merge of the newest `n` tumbling windows /// reads the first `n`, the same nodes a merge of the whole chain reads. Every other node keeps its -/// guarantee, timing and materialization. Each tumbling window takes its chain's -/// timing and materialization, and the range and shift it reads take the +/// guarantee, timing and lifetime. Each tumbling window takes its chain's +/// timing and lifetime, and the range and shift it reads take the /// chain's timing: a chain materialized at ingestion time expands into /// tumbling windows each built and stored at ingestion time. Expanding before timings /// are applied leaves the tumbling windows untimed. A chain read by anything but a @@ -341,7 +341,7 @@ fn timed_like(node: &Rc, timing: ExecutionTiming) -> OperatorNode node.schema.clone(), ) .with_guarantee(node.guarantee.clone()) - .with_materialization(node.materialization) + .with_lifetime(node.lifetime) .with_timing(Some(timing)) } @@ -393,7 +393,7 @@ fn expand( let tumbling_window = match child.timing { Some(timing) => Rc::new( timed_like(&tumbling_window, timing) - .with_materialization(child.materialization), + .with_lifetime(child.lifetime), ), None => tumbling_window, }; @@ -418,7 +418,7 @@ fn expand( OperatorNode::with_schema(merge.operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } _ => { @@ -438,7 +438,7 @@ fn expand( ) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } else { Rc::clone(node) diff --git a/crates/types/src/ir/physical_export.rs b/crates/types/src/ir/physical_export.rs index ccb07e256..4a1ab49c8 100644 --- a/crates/types/src/ir/physical_export.rs +++ b/crates/types/src/ir/physical_export.rs @@ -1,11 +1,11 @@ //! Physical ASAP DAG (planner-layering stage 2 output). //! -//! The flattened operators of [`super::flat`], plus the materialization and +//! The flattened operators of [`super::flat`], plus the lifetime and //! execution timing (data state) of every node and edge. The input must //! already be timed ([`crate::ir::properties::timing::apply_materialization_timings`]); export -//! reads each node's timing and materialization and does not re-run +//! reads each node's timing and lifetime and does not re-run //! data-state validation. The deployment executes the plan as given -//! (#509 Assumption 8): it does not change materialization or timing. +//! (#509 Assumption 8): it does not change lifetime or timing. use std::collections::{HashMap, HashSet}; use std::rc::Rc; @@ -30,7 +30,7 @@ use crate::ir::properties::timing::{ }; use crate::ir::properties::timing::{data_state, is_materialization_point}; use crate::ir::schema::{FieldDataType, Schema}; -use crate::physical::materialization::Materialization; +use crate::physical::{Lifetime, PhysicalProperties}; /// A node's operator, with each child replaced by its node id. pub type PhysicalASAPOperatorPayload = Operator; @@ -71,22 +71,23 @@ pub struct PhysicalASAPDAGNode { pub payload: PhysicalASAPOperatorPayload, /// Phase is a placement choice for every operator, independent of payload kind. pub output_state: ExecutionDataState, - /// Whether and where the deployment stores this node's output: the - /// option the materialization assignment chose for the sub-DAG this node - /// produces. Any node may be stored (#509 §Materialization); a node with - /// no assignment is `NotMaterialized`. - pub materialization: Materialization, + /// How long and where the deployment keeps this node's output: the + /// lifetime the materialization assignment chose for the sub-DAG this + /// node produces. Any node may be kept (#509 §Materialization); a node + /// with no assignment has lifetime `None`. With `output_state.timing` it + /// is the node's [`PhysicalProperties`]. + pub lifetime: Lifetime, pub output_schema: Schema, pub guarantee: Option, - /// For a materialized view (a node whose materialization keeps its - /// output across evaluations), how far back from the newest evaluation + /// For a materialized view (a node whose lifetime keeps its output + /// across evaluations), how far back from the newest evaluation /// time its output must stay available once refreshed; for a query-time /// `Scan`, how far back its source's rows must stay available (`None` /// when it reads them unbounded). `None` on every other node, and on /// every node of a DAG exported before installation sets it /// ([`PhysicalASAPDAG::set_retention`]). A - /// node field rather than part of [`Materialization`], because Stage 2 - /// enumerates materializations before Stage 3 knows retention. + /// node field rather than part of [`Lifetime`], because Stage 2 + /// enumerates lifetimes before Stage 3 knows retention. #[serde(default, skip_serializing_if = "Option::is_none")] pub retention_ms: Option, } @@ -172,12 +173,13 @@ pub struct PhysicalASAPDAG { #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum PhysicalASAPDAGValidationError { #[error( - "node {node:?} runs at {timing:?}, which its materialization {materialization:?} does not" + "node {node:?} runs at {timing:?} with lifetime {lifetime:?}: a timing and lifetime that \ + cannot go together, or a summary build that is not kept outside query time" )] - MaterializationTimingMismatch { + InvalidPhysicalProperties { node: PhysicalASAPNodeId, timing: ExecutionTiming, - materialization: Materialization, + lifetime: Lifetime, }, #[error("ingestion node {consumer:?} depends on query node {producer:?}")] QueryDependencyInIngestion { @@ -352,7 +354,7 @@ pub enum ReferencePlanError { impl PhysicalASAPDAG { /// This DAG's plan with nothing materialized: the same operators, /// summaries and summary parameters, with every sub-DAG - /// `NotMaterialized` and so every node at query time (the default + /// not kept and so every node at query time (the default /// [`MaterializationAssignment`]). Node ids are renumbered, and `roots` /// and `scalar_roots` keep their order. /// @@ -369,7 +371,7 @@ impl PhysicalASAPDAG { } /// Every node of this DAG as IR, by node id, untimed and - /// `NotMaterialized` with its exported guarantee: what a caller derives + /// not kept with its exported guarantee: what a caller derives /// IR properties of a plan file's node from, such as its /// [`SummaryCoverage`](crate::ir::properties::summary_coverage::SummaryCoverage). /// Shared inputs stay shared. Validates the DAG first. @@ -568,7 +570,7 @@ impl PhysicalASAPDAG { } /// The IR this DAG exports, one root per query in batch order, every - /// node untimed and `NotMaterialized`: the inverse of + /// node untimed and not kept: the inverse of /// [`compile_physical_asap_workload`] up to `Rc` identity and timing. #[cfg(any(test, feature = "test-support"))] fn untimed_query_roots(&self) -> Result, PhysicalASAPDAGValidationError> { @@ -599,22 +601,23 @@ impl PhysicalASAPDAG { if nodes.insert(node.id, node).is_some() { return Err(PhysicalASAPDAGValidationError::DuplicateNodeId(node.id)); } - // A sub-DAG output runs when its materialization says; any other - // node is not stored and runs when its consumer runs. - if (is_materialization_point(&node.payload) - || node.materialization != Materialization::NotMaterialized) - && node.materialization.timing() != node.output_state.timing + // A kept output's timing and lifetime must go together; a summary + // build that is not kept runs at query time. Any other node that + // is not kept runs when its consumer runs. + let timing = node.output_state.timing; + if PhysicalProperties::new(timing, node.lifetime).is_err() + || (is_materialization_point(&node.payload) + && node.lifetime == Lifetime::None + && timing != ExecutionTiming::QueryTime) { - return Err( - PhysicalASAPDAGValidationError::MaterializationTimingMismatch { - node: node.id, - timing: node.output_state.timing, - materialization: node.materialization, - }, - ); + return Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { + node: node.id, + timing, + lifetime: node.lifetime, + }); } if node.retention_ms.is_some() - && !node.materialization.is_materialized_view() + && !matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) && !super::materialized_view::is_query_time_scan(node) { return Err(PhysicalASAPDAGValidationError::UnexpectedRetention(node.id)); @@ -902,7 +905,7 @@ pub fn compile_physical_asap_workload_with_node_ids( id, payload: flat_node.operator, output_state, - materialization: flat_node.materialization, + lifetime: flat_node.lifetime, output_schema: flat_node.schema, guarantee: flat_node.guarantee, retention_ms: None, diff --git a/crates/types/src/ir/properties/execution_data_state.rs b/crates/types/src/ir/properties/execution_data_state.rs index e3a2cda8e..6a1e23b42 100644 --- a/crates/types/src/ir/properties/execution_data_state.rs +++ b/crates/types/src/ir/properties/execution_data_state.rs @@ -2,14 +2,15 @@ //! //! [`ExecutionTiming`] says when a node's value is produced (ingestion vs. //! query time); [`ExecutionDataState`] pairs it with the [`DataPrimitive`] -//! the edge carries (raw values vs. summary state). [`Materialization`] is -//! the per-sub-DAG choice a node's timing is derived from. The rules that assign +//! the edge carries (raw values vs. summary state). A kept output's +//! [`PhysicalProperties`] are the per-sub-DAG choice a node's timing is +//! derived from. The rules that assign //! and check them over a DAG live in [`crate::ir::properties::timing`], which reports //! violations as [`ExecutionDataStateError`]. use thiserror::Error; -use crate::physical::Materialization; +use crate::physical::PhysicalProperties; /// When a post-ASAP value is produced. #[derive( @@ -99,11 +100,11 @@ pub enum ExecutionDataStateError { }, /// A summary build at query time over an input (rows or exact-accumulator /// state) produced at ingestion time and not stored there (the input node - /// is not `MatAtIngestion`): at query time that input no longer exists. + /// is not kept at ingestion time): at query time that input no longer exists. /// Bad input (a hand-built or candidate-fixed plan), not an internal bug. #[error( "a query-time {edge} reads {operator} output produced at ingestion time that is not \ - stored (not MatAtIngestion)" + stored (not kept at ingestion time)" )] UnstoredIngestionInputUnderQueryTimeSummary { edge: &'static str, @@ -134,10 +135,10 @@ pub enum ExecutionDataStateError { }, /// A plan root that runs at ingestion time without being stored there /// (a timing fixed by a candidate builder): no query reads its rows. A - /// root assigned `MatAtIngestion` is valid; the query reads the stored + /// root assigned kept at ingestion time is valid; the query reads the stored /// output. #[error( - "{operator} root runs at ingestion time but is not MatAtIngestion: no query reads its \ + "{operator} root runs at ingestion time but is not kept there: no query reads its \ output" )] UnstoredIngestionRoot { operator: &'static str }, @@ -145,14 +146,14 @@ pub enum ExecutionDataStateError { /// fixed (e.g. a query-time `FinalizeExactAccumulator` read boundary) /// that needs the other timing. #[error( - "{operator} is fixed at {} by its candidate; materialization {materialization:?} needs \ + "{operator} is fixed at {} by its candidate; its assigned kept output {assigned:?} needs \ the other timing", fixed.as_str() )] MaterializationConflictsWithFixedTiming { operator: &'static str, fixed: ExecutionTiming, - materialization: Materialization, + assigned: PhysicalProperties, }, /// A summary build with a filter placed at ingestion time. An /// ingestion-time build reads raw data samples, which carry none of the @@ -177,7 +178,7 @@ pub enum ExecutionDataStateError { /// `SummaryJoin` and `Extension`. #[error("{operator} has no execution timing contract yet")] UnimplementedOperator { operator: &'static str }, - /// A node assigned `MatAtIngestion` over a sub-DAG that can only run at + /// A node assigned kept at ingestion time over a sub-DAG that can only run at /// query time (#509 Algorithm 3, line 13). #[error("{operator}: upstream of ingestion-time node not at ingestion time")] UpstreamNotAtIngestion { operator: &'static str }, diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index 07684c9fc..f7630c64d 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -3,37 +3,37 @@ //! edges. //! //! The logical DAG carries no timing. Materialization (#509 -//! §Materialization) gives each sub-DAG one of its options: -//! `NotMaterialized`, `MatAtIngestion(medium)`, `MatAtQuery(medium)` or -//! `MatAtQueryKeptAcrossEvaluations(medium)`. -//! [`MaterializationAssignment`] records that option per sub-DAG, named by -//! the node whose output would be stored (any node: a summary state, a -//! population, or e.g. the tumbling windows of #509 Example 4), and -//! [`apply_materialization_timings`] expands it into a timing on every node: +//! §Materialization) decides, for each sub-DAG, whether its output is kept, +//! and if so with which [`PhysicalProperties`]: its timing and its +//! [`Lifetime`] (#1200). [`MaterializationAssignment`] records that per +//! sub-DAG, named by the node whose output would be kept (any node: a +//! summary state, a population, or e.g. the tumbling windows of #509 +//! Example 4), and [`apply_materialization_timings`] expands it into a +//! timing and a lifetime on every node: //! //! - `SummaryEstimate` and `EvaluatePopulation` run at query time; -//! - a node assigned `MatAtIngestion` runs at ingestion time, and one -//! assigned `MatAtQuery` or `MatAtQueryKeptAcrossEvaluations` at query -//! time. A `SummaryAgg` or -//! `MaintainPopulation` without an assignment is `NotMaterialized` and runs -//! at query time. Every node upstream of an ingestion-time node also runs -//! at ingestion time, so `MatAtIngestion` (or an ingestion timing fixed by -//! a candidate builder) over something that can only exist at query time -//! is an error ([`ExecutionDataStateError::UpstreamNotAtIngestion`]); +//! - a node assigned a kept output runs at that output's timing. A +//! `SummaryAgg` or `MaintainPopulation` without an assignment is not kept +//! and runs at query time. Every node upstream of an ingestion-time node +//! also runs at ingestion time, so a kept ingestion-time output (or an +//! ingestion timing fixed by a candidate builder) over something that can +//! only exist at query time is an error +//! ([`ExecutionDataStateError::UpstreamNotAtIngestion`]); //! - a PromQL `BinaryOp` over per-series inputs that are not the same series //! rows runs at query time, since maintenance cannot align them; -//! - every other node is `NotMaterialized` and runs when its consumer runs: -//! everything that feeds an ingestion-time node runs at ingestion time, -//! everything above an evaluation at query time. +//! - every other node is not kept (lifetime `None`) and runs when its +//! consumer runs: everything that feeds an ingestion-time node runs at +//! ingestion time, everything above an evaluation at query time. //! //! A node whose timing a candidate builder fixed (e.g. the query-time //! `FinalizeExactAccumulator` of `finalize_query_candidate`) keeps that //! timing. An explicit assignment on it that agrees is kept; one that needs //! the other timing is an error //! ([`ExecutionDataStateError::MaterializationConflictsWithFixedTiming`]). -//! A root may be `MatAtIngestion`: the query reads its stored output. A root -//! of rows that runs at ingestion time without being stored there is an -//! error ([`ExecutionDataStateError::UnstoredIngestionRoot`]). +//! A root may be kept at ingestion time across evaluations: the query reads +//! its stored output. A root of rows that runs at ingestion time without +//! being kept there is an error +//! ([`ExecutionDataStateError::UnstoredIngestionRoot`]). //! //! A node reached from two consumers that need different timings cannot be //! executed once for both; Stage 2's `split_shared_by_timing` copies such a @@ -45,13 +45,13 @@ //! //! | Consumer | Accepts from an input | //! |---|---| -//! | `SummaryAgg.child`, `SummaryTumblingWindowChain.child` | Rows, or exact-accumulator state, never a query-time value when the state is maintained; a query-time build reads an ingestion-time input (rows or exact-accumulator state) only as a `MatAtIngestion` input's stored output | +//! | `SummaryAgg.child`, `SummaryTumblingWindowChain.child` | Rows, or exact-accumulator state, never a query-time value when the state is maintained; a query-time build reads an ingestion-time input (rows or exact-accumulator state) only as a kept at ingestion time input's stored output | //! | `SummaryEstimate.summary_input` | Summary state at either timing | //! | `SummaryMerge.children` | Summary state at either timing; at ingestion time only for a merge at ingestion time | //! | `FinalizeExactAccumulator.child` | Exact-accumulator state | //! | `EvaluatePopulation.child` | A timed `MaintainPopulation` | -//! | `MaintainPopulation.child` | Rows at its own timing matching the population's input; unlike a `NonASAP` consumer, a query-time population does not read a `MatAtIngestion` input's stored output | -//! | any `NonASAP` consumer | Rows (or exact-accumulator state for a projection-like operator) at the consumer's own timing, or a `MatAtIngestion` output read at query time; ingestion work never reads a query-time value | +//! | `MaintainPopulation.child` | Rows at its own timing matching the population's input; unlike a `NonASAP` consumer, a query-time population does not read a kept at ingestion time input's stored output | +//! | any `NonASAP` consumer | Rows (or exact-accumulator state for a projection-like operator) at the consumer's own timing, or an output kept at ingestion time read at query time; ingestion work never reads a query-time value | use std::collections::HashMap; use std::rc::Rc; @@ -65,24 +65,24 @@ use crate::ir::properties::execution_data_state::{ DataPrimitive, ExecutionDataState, ExecutionDataStateError, ExecutionTiming, }; use crate::ir::schema::{DataType, FieldDataType, Schema}; -use crate::physical::materialization::Materialization; #[cfg(any(test, feature = "test-support"))] -use crate::physical::materialization::Medium; - -/// The materialization option of each sub-DAG (#509 §Materialization: -/// "Materialization decides, for each sub-DAG, whether its output is -/// stored"). A sub-DAG is named by the node whose output would be stored (by -/// identity); any node may be assigned. A node without an assignment is not -/// stored: a `SummaryAgg` or `MaintainPopulation` takes the default, every -/// other node runs when its consumer runs. `Default` assigns -/// `NotMaterialized` to every sub-DAG. +use crate::physical::Medium; +use crate::physical::{Lifetime, PhysicalProperties}; + +/// Whether each sub-DAG's output is kept, and with which timing and +/// lifetime (#509 §Materialization: "Materialization decides, for each +/// sub-DAG, whether its output is stored"). A sub-DAG is named by the node +/// whose output would be kept (by identity); any node may be assigned. A +/// node without an assignment: a `SummaryAgg` or `MaintainPopulation` takes +/// the default, every other node is not kept and runs when its consumer +/// runs. `Default` keeps no sub-DAG. /// /// The assignment keeps every assigned node alive, so a later allocation /// cannot reuse its address and match a stale entry. #[derive(Clone, Default)] pub struct MaterializationAssignment { - assigned: HashMap<*const OperatorNode, (Rc, Materialization)>, - unassigned: Materialization, + assigned: HashMap<*const OperatorNode, (Rc, Option)>, + unassigned: Option, } /// Each assigned node as its operator kind and address, not its whole @@ -92,11 +92,8 @@ impl std::fmt::Debug for MaterializationAssignment { let assigned: Vec<_> = self .assigned .iter() - .map(|(ptr, (node, materialization))| { - ( - format!("{}@{ptr:p}", node.operator.kind_name()), - materialization, - ) + .map(|(ptr, (node, properties))| { + (format!("{}@{ptr:p}", node.operator.kind_name()), properties) }) .collect(); f.debug_struct("MaterializationAssignment") @@ -108,27 +105,32 @@ impl std::fmt::Debug for MaterializationAssignment { impl MaterializationAssignment { /// Every `SummaryAgg` or `MaintainPopulation` not [`set`](Self::set) - /// explicitly takes `materialization` where the DAG allows it: a - /// `MatAtIngestion` default over a sub-DAG that can only run at query - /// time leaves that sub-DAG `NotMaterialized`. - pub fn with_default(materialization: Materialization) -> Self { + /// explicitly takes `kept` where the DAG allows it: an ingestion-time + /// default over a sub-DAG that can only run at query time leaves that + /// sub-DAG not kept. + pub fn with_default(kept: Option) -> Self { Self { assigned: HashMap::new(), - unassigned: materialization, + unassigned: kept, } } - /// Assign `materialization` to the sub-DAG whose output `node` produces. - pub fn set(&mut self, node: &Rc, materialization: Materialization) { + /// Assign the sub-DAG whose output `node` produces: kept with `kept`'s + /// timing and lifetime, or, for `None`, not kept (it runs when its + /// consumer runs). A `Some` with lifetime `None` is not an assignment of + /// a kept output. + pub fn set(&mut self, node: &Rc, kept: Option) { + debug_assert!(kept.is_none_or(|p| p.lifetime().is_kept())); self.assigned - .insert(Rc::as_ptr(node), (Rc::clone(node), materialization)); + .insert(Rc::as_ptr(node), (Rc::clone(node), kept)); } - /// The explicit assignment of `node`, if any. - pub fn get(&self, node: &OperatorNode) -> Option { + /// The explicit assignment of `node`, if any: `Some(None)` when it is + /// explicitly not kept. + pub fn get(&self, node: &OperatorNode) -> Option> { self.assigned .get(&(node as *const OperatorNode)) - .map(|(_, m)| *m) + .map(|(_, kept)| *kept) } /// The option `node` gets when `upstream_at_query_time` says whether @@ -137,8 +139,10 @@ impl MaterializationAssignment { &self, node: &OperatorNode, upstream_at_query_time: bool, - ) -> Result { - let at_ingestion = |m: Materialization| m.timing() == ExecutionTiming::IngestionTime; + ) -> Result, ExecutionDataStateError> { + let at_ingestion = |kept: Option| { + kept.is_some_and(|p| p.timing() == ExecutionTiming::IngestionTime) + }; match self.get(node) { Some(m) if at_ingestion(m) && is_filtered_build(node) => { Err(ExecutionDataStateError::FilteredSummaryAtIngestion { @@ -154,7 +158,7 @@ impl MaterializationAssignment { None if at_ingestion(self.unassigned) && (upstream_at_query_time || is_filtered_build(node)) => { - Ok(Materialization::NotMaterialized) + Ok(None) } None => Ok(self.unassigned), } @@ -261,12 +265,9 @@ fn forces_query_time( { let upstream = upstream(seen); match assignment.resolve(node, upstream) { - Ok(Materialization::NotMaterialized) - if !is_materialization_point(&node.operator) => - { - upstream - } - Ok(m) => m.timing() == ExecutionTiming::QueryTime, + Ok(None) if !is_materialization_point(&node.operator) => upstream, + Ok(None) => true, + Ok(Some(kept)) => kept.timing() == ExecutionTiming::QueryTime, Err(_) => true, } } @@ -305,7 +306,7 @@ pub fn apply_materialization_timings( // A root stored at ingestion time is read by the query; one that runs at // ingestion time without being stored there produces rows nothing reads. if timed.timing == Some(ExecutionTiming::IngestionTime) - && !matches!(timed.materialization, Materialization::MatAtIngestion(_)) + && !kept_at_ingestion(&timed) && data_state(&timed).map(|s| s.primitive) == Some(DataPrimitive::Raw) { return Err(ExecutionDataStateError::UnstoredIngestionRoot { @@ -345,7 +346,7 @@ pub fn apply_materialization_timings_to_roots( .collect() } -/// Validate the sub-DAG below `root` with every sub-DAG `MatAtIngestion` +/// Validate the sub-DAG below `root` with every sub-DAG kept at ingestion time /// where the DAG allows it ([`MaterializationAssignment::with_default`]) and /// `root` consumed at `root_timing`. For planning-time legality checks of a /// candidate before it is assembled into a workload DAG: a candidate must stay @@ -363,7 +364,7 @@ pub fn validate_at_ingestion( validate(&timed, &mut HashMap::new()) } -/// The data state `node` produces with every sub-DAG `MatAtIngestion` where +/// The data state `node` produces with every sub-DAG kept at ingestion time where /// the DAG allows it, when its consumer runs at `consumer` — the planning-time answer to /// "what does this candidate's output look like", consistent with /// [`validate_at_ingestion`]. @@ -384,17 +385,30 @@ pub fn planned_data_state( /// The assignment of [`validate_at_ingestion`] and [`planned_data_state`]. #[cfg(any(test, feature = "test-support"))] fn all_at_ingestion() -> MaterializationAssignment { - MaterializationAssignment::with_default(Materialization::MatAtIngestion(Medium::Memory)) + MaterializationAssignment::with_default(Some( + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .expect("ingestion time, kept across evaluations"), + )) } -/// The timing and materialization `node` takes when its consumer runs at +/// Whether `node`'s output runs at ingestion time and is kept until a query +/// reads it. +fn kept_at_ingestion(node: &OperatorNode) -> bool { + node.timing == Some(ExecutionTiming::IngestionTime) + && matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) +} + +/// The timing and lifetime `node` takes when its consumer runs at /// `consumer`. fn placement( node: &Rc, consumer: ExecutionTiming, assignment: &MaterializationAssignment, forced: &mut HashMap<*const OperatorNode, bool>, -) -> Result<(ExecutionTiming, Materialization), ExecutionDataStateError> { +) -> Result<(ExecutionTiming, Lifetime), ExecutionDataStateError> { // A placement fixed when the candidate was built (an exact-state read // boundary that must run at query time, or one that feeds maintenance) // is honored; a conflicting consumer is rejected by validation. @@ -418,38 +432,39 @@ fn placement( // with the fixed timing is kept, one that needs the other timing is // an error. return match assignment.get(node) { - Some(m) if m != Materialization::NotMaterialized && m.timing() != placed => Err( + Some(Some(kept)) if kept.timing() != placed => Err( ExecutionDataStateError::MaterializationConflictsWithFixedTiming { operator: node.operator.kind_name(), fixed: placed, - materialization: m, + assigned: kept, }, ), - Some(m) => Ok((placed, m)), - None => Ok((placed, node.materialization)), + Some(Some(kept)) => Ok((placed, kept.lifetime())), + Some(None) => Ok((placed, Lifetime::None)), + None => Ok((placed, node.lifetime)), }; } Ok(match &node.operator { Operator::ASAP(ASAPOp::SummaryEstimate { .. }) | Operator::ASAP(ASAPOp::EvaluatePopulation { .. }) => match assignment.get(node) { - Some(m) if m.timing() == ExecutionTiming::IngestionTime => { + Some(Some(kept)) if kept.timing() == ExecutionTiming::IngestionTime => { return Err(ExecutionDataStateError::UpstreamNotAtIngestion { operator: node.operator.kind_name(), }) } - Some(m) => (ExecutionTiming::QueryTime, m), - None => (ExecutionTiming::QueryTime, Materialization::NotMaterialized), + Some(Some(kept)) => (ExecutionTiming::QueryTime, kept.lifetime()), + Some(None) | None => (ExecutionTiming::QueryTime, Lifetime::None), }, _ if is_materialization_point(&node.operator) || assignment.get(node).is_some() => { let upstream = upstream_at_query_time(forced); match assignment.resolve(node, upstream)? { - Materialization::NotMaterialized if !is_materialization_point(&node.operator) => { - (consumer, Materialization::NotMaterialized) - } - materialization => (materialization.timing(), materialization), + None if !is_materialization_point(&node.operator) => (consumer, Lifetime::None), + // A summary build that is not kept runs at query time. + None => (ExecutionTiming::QueryTime, Lifetime::None), + Some(kept) => (kept.timing(), kept.lifetime()), } } - _ => (consumer, Materialization::NotMaterialized), + _ => (consumer, Lifetime::None), }) } @@ -477,7 +492,7 @@ fn write( cache: &mut NodeToTimedNodeCache, forced: &mut HashMap<*const OperatorNode, bool>, ) -> Result, ExecutionDataStateError> { - let (timing, materialization) = placement(node, consumer, assignment, forced)?; + let (timing, lifetime) = placement(node, consumer, assignment, forced)?; if let Some(done) = cache.timed_node_of.get(&Rc::as_ptr(node)) { let previous = done.timing.expect("memoized node is timed"); if previous != timing { @@ -512,7 +527,7 @@ fn write( OperatorNode::with_schema(operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(Some(timing)) - .with_materialization(materialization), + .with_lifetime(lifetime), ); cache .timed_node_of @@ -588,7 +603,7 @@ fn validate_asap( // `NonASAP` consumer does. if timing == ExecutionTiming::QueryTime && avail.timing == ExecutionTiming::IngestionTime - && child.materialization.timing() != ExecutionTiming::IngestionTime + && !kept_at_ingestion(child) { return Err( ExecutionDataStateError::UnstoredIngestionInputUnderQueryTimeSummary { @@ -739,8 +754,7 @@ fn validate_non_asap( && (is_exact_accumulator_state(&child.schema).is_ok() || selects_states(node)); // A query-time consumer may read the stored output of a sub-DAG // materialized at ingestion time. - let reads_stored = timing == ExecutionTiming::QueryTime - && child.materialization.timing() == ExecutionTiming::IngestionTime; + let reads_stored = timing == ExecutionTiming::QueryTime && kept_at_ingestion(child); if (s.timing != timing && !reads_stored) || (s.primitive != DataPrimitive::Raw && !passes_state) { @@ -977,19 +991,28 @@ mod tests { ) } - /// Apply with every sub-DAG `MatAtIngestion` where the DAG allows it, the + /// Apply with every sub-DAG kept at ingestion time where the DAG allows it, the /// placement whose edge rules these tests exercise. fn apply(root: &Rc) -> Result, ExecutionDataStateError> { apply_materialization_timings(root, &all_at_ingestion(), &mut NodeToTimedNodeCache::new()) } - const AT_INGESTION: Materialization = Materialization::MatAtIngestion(Medium::Memory); + const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); + + fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> Option { + Some(PhysicalProperties::new(timing, lifetime).unwrap()) + } + + /// Kept at ingestion time across evaluations. + fn at_ingestion() -> Option { + kept(ExecutionTiming::IngestionTime, KEPT_ACROSS) + } fn child(node: &Rc) -> Rc { Rc::clone(node.children()[0]) } - /// Without a materialization decision, a summary is `NotMaterialized` and + /// Without a materialization decision, a summary is not kept and /// it and its input run at query time; an explicit choice overrides the /// default and is recorded on the timed node. #[test] @@ -1008,20 +1031,20 @@ mod tests { primitive: DataPrimitive::SummaryState, }) ); - assert_eq!(root.materialization, Materialization::NotMaterialized); + assert_eq!(root.lifetime, Lifetime::None); assert_eq!( data_state(&child(&root)), Some(ExecutionDataState::QUERY_ROWS) ); - for (materialization, timing) in [ - (AT_INGESTION, ExecutionTiming::IngestionTime), + for (lifetime, timing) in [ + (KEPT_ACROSS, ExecutionTiming::IngestionTime), ( - Materialization::MatAtQuery(Medium::Disk), + Lifetime::OneEvaluation(Medium::Disk), ExecutionTiming::QueryTime, ), ] { let mut assignment = MaterializationAssignment::default(); - assignment.set(&summary, materialization); + assignment.set(&summary, kept(timing, lifetime)); let root = apply_materialization_timings( &summary, &assignment, @@ -1029,16 +1052,13 @@ mod tests { ) .unwrap(); assert_eq!(root.timing, Some(timing)); - assert_eq!(root.materialization, materialization); + assert_eq!(root.lifetime, lifetime); assert_eq!(child(&root).timing, Some(timing)); - assert_eq!( - child(&root).materialization, - Materialization::NotMaterialized - ); + assert_eq!(child(&root).lifetime, Lifetime::None); } } - /// #509 Algorithm 3, line 13: an explicit `MatAtIngestion` over a state + /// #509 Algorithm 3, line 13: an explicit assignment kept at ingestion time over a state /// that only exists at query time is an error, not a silent move to /// query time. #[test] @@ -1046,7 +1066,7 @@ mod tests { let inner = agg(scan(), exact_sum()); let outer = agg(Rc::clone(&inner), kll()); let mut assignment = MaterializationAssignment::default(); - assignment.set(&outer, AT_INGESTION); + assignment.set(&outer, at_ingestion()); assert_eq!( apply_materialization_timings( &estimate(outer), @@ -1058,17 +1078,17 @@ mod tests { operator: "SummaryAgg" }) ); - assignment.set(&inner, AT_INGESTION); + assignment.set(&inner, at_ingestion()); let outer = agg(Rc::clone(&inner), kll()); - assignment.set(&outer, AT_INGESTION); + assignment.set(&outer, at_ingestion()); let root = apply_materialization_timings( &estimate(outer), &assignment, &mut NodeToTimedNodeCache::new(), ) .unwrap(); - assert_eq!(child(&root).materialization, AT_INGESTION); - assert_eq!(child(&child(&root)).materialization, AT_INGESTION); + assert_eq!(child(&root).lifetime, KEPT_ACROSS); + assert_eq!(child(&child(&root)).lifetime, KEPT_ACROSS); } #[test] @@ -1091,14 +1111,14 @@ mod tests { } /// A state not at ingestion time leaves the summary that reads it, when - /// that summary has no explicit assignment, `NotMaterialized` at query + /// that summary has no explicit assignment, not kept at query /// time, as an evaluation below it would. #[test] fn query_time_state_moves_its_consuming_summary_to_query_time() { let inner = agg(scan(), exact_sum()); let outer = agg(Rc::clone(&inner), kll()); let mut assignment = all_at_ingestion(); - assignment.set(&inner, Materialization::NotMaterialized); + assignment.set(&inner, None); let root = apply_materialization_timings( &estimate(outer), &assignment, @@ -1107,7 +1127,7 @@ mod tests { .unwrap(); let outer = child(&root); assert_eq!(outer.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(outer.materialization, Materialization::NotMaterialized); + assert_eq!(outer.lifetime, Lifetime::None); assert_eq!(child(&outer).timing, Some(ExecutionTiming::QueryTime)); } @@ -1192,7 +1212,7 @@ mod tests { } /// A finalize pinned to ingestion time (as fixed-window rate candidates - /// build it) over a state that is not `MatAtIngestion` names the missing + /// build it) over a state that is not kept at ingestion time names the missing /// upstream, not an illegal edge. #[test] fn ingestion_pinned_finalize_over_query_time_state_is_upstream_not_at_ingestion() { @@ -1225,12 +1245,12 @@ mod tests { let tumbling_windows = max(scan()); let root = max(Rc::clone(&tumbling_windows)); let mut assignment = MaterializationAssignment::default(); - assignment.set(&tumbling_windows, AT_INGESTION); + assignment.set(&tumbling_windows, at_ingestion()); let timed = apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).materialization, AT_INGESTION); + assert_eq!(child(&timed).lifetime, KEPT_ACROSS); assert_eq!(child(&timed).timing, Some(ExecutionTiming::IngestionTime)); assert_eq!( child(&child(&timed)).timing, @@ -1239,7 +1259,7 @@ mod tests { let over_evaluation = max(estimate(agg(scan(), kll()))); let mut assignment = MaterializationAssignment::default(); - assignment.set(&over_evaluation, AT_INGESTION); + assignment.set(&over_evaluation, at_ingestion()); assert_eq!( apply_materialization_timings( &over_evaluation, @@ -1255,7 +1275,7 @@ mod tests { /// A summary build with a filter never runs at ingestion time: an /// ingestion-time build reads raw data samples, which carry none of the - /// query's columns the filter reads. An explicit `MatAtIngestion` is an + /// query's columns the filter reads. An explicit assignment kept at ingestion time is an /// error; the all-at-ingestion default leaves it at query time. #[test] fn a_filtered_summary_build_never_runs_at_ingestion_time() { @@ -1288,7 +1308,7 @@ mod tests { .with_guarantee(None), ); let mut assignment = MaterializationAssignment::default(); - assignment.set(&filtered, AT_INGESTION); + assignment.set(&filtered, at_ingestion()); assert_eq!( apply_materialization_timings( &estimate(Rc::clone(&filtered)), @@ -1302,10 +1322,7 @@ mod tests { ); let timed = apply(&estimate(filtered)).unwrap(); assert_eq!(child(&timed).timing, Some(ExecutionTiming::QueryTime)); - assert_eq!( - child(&timed).materialization, - Materialization::NotMaterialized - ); + assert_eq!(child(&timed).lifetime, Lifetime::None); assert!(validate_at_ingestion(&child(&timed), ExecutionTiming::QueryTime).is_ok()); } @@ -1316,15 +1333,15 @@ mod tests { .unwrap() } - /// The materialization the exported DAG records for `node`'s operator kind. - fn exported(root: &Rc, kind: &str) -> Materialization { + /// The lifetime the exported DAG records for `node`'s operator kind. + fn exported(root: &Rc, kind: &str) -> Lifetime { let dag = crate::ir::physical_export::compile_physical_asap_dag(root).unwrap(); dag.validate().unwrap(); dag.nodes .iter() .find(|n| n.payload.kind_name() == kind) .unwrap() - .materialization + .lifetime } /// A node whose timing its candidate fixed (the query-time read boundary @@ -1338,19 +1355,19 @@ mod tests { .clone() .with_timing(Some(ExecutionTiming::QueryTime)), ); - let stored = Materialization::MatAtQuery(Medium::Disk); + let stored = Lifetime::OneEvaluation(Medium::Disk); let mut assignment = MaterializationAssignment::default(); - assignment.set(&read, stored); + assignment.set(&read, kept(ExecutionTiming::QueryTime, stored)); let timed = apply_materialization_timings(&read, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(timed.materialization, stored); + assert_eq!(timed.lifetime, stored); assert_eq!(exported(&timed, "FinalizeExactAccumulator"), stored); let mut assignment = MaterializationAssignment::default(); - assignment.set(&state, AT_INGESTION); - assignment.set(&read, AT_INGESTION); + assignment.set(&state, at_ingestion()); + assignment.set(&read, at_ingestion()); assert_eq!( apply_materialization_timings(&read, &assignment, &mut NodeToTimedNodeCache::new()) .err(), @@ -1358,7 +1375,7 @@ mod tests { ExecutionDataStateError::MaterializationConflictsWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - materialization: AT_INGESTION, + assigned: at_ingestion().unwrap(), } ) ); @@ -1369,19 +1386,22 @@ mod tests { #[test] fn debug_names_each_assigned_node_by_its_kind() { let mut assignment = MaterializationAssignment::default(); - assignment.set(&agg(scan(), kll()), AT_INGESTION); + assignment.set(&agg(scan(), kll()), at_ingestion()); let text = format!("{assignment:?}"); assert!(text.contains("SummaryAgg@"), "{text}"); assert!(!text.contains("fields"), "{text}"); } - /// A node fixed at ingestion time by its candidate rejects a `MatAtQuery` + /// A node fixed at ingestion time by its candidate rejects a `OneEvaluation` /// assignment, which needs the other timing. #[test] fn ingestion_fixed_node_rejects_mat_at_query() { let fixed = placed_at_ingestion(max(scan())); let root = max(Rc::clone(&fixed)); - let at_query = Materialization::MatAtQuery(Medium::Memory); + let at_query = kept( + ExecutionTiming::QueryTime, + Lifetime::OneEvaluation(Medium::Memory), + ); let mut assignment = MaterializationAssignment::default(); assignment.set(&fixed, at_query); assert_eq!( @@ -1391,15 +1411,15 @@ mod tests { ExecutionDataStateError::MaterializationConflictsWithFixedTiming { operator: "Aggregate", fixed: ExecutionTiming::IngestionTime, - materialization: at_query, + assigned: at_query.unwrap(), } ) ); } - /// An explicit `NotMaterialized` on a node whose timing its candidate + /// An explicit not kept on a node whose timing its candidate /// fixed agrees with either timing: the node keeps its fixed timing and - /// records `NotMaterialized`. + /// records not kept. #[test] fn explicit_not_materialized_keeps_a_fixed_timing() { let read = Rc::new( @@ -1409,13 +1429,13 @@ mod tests { ); let root = max(Rc::clone(&read)); let mut assignment = MaterializationAssignment::default(); - assignment.set(&read, Materialization::NotMaterialized); + assignment.set(&read, None); let timed = apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let read = child(&timed); assert_eq!(read.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(read.materialization, Materialization::NotMaterialized); + assert_eq!(read.lifetime, Lifetime::None); } /// A query-time summary build cannot read ingestion-time rows that are @@ -1441,12 +1461,12 @@ mod tests { ); let mut assignment = MaterializationAssignment::default(); - assignment.set(&rows, AT_INGESTION); + assignment.set(&rows, at_ingestion()); let timed = apply_materialization_timings(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).materialization, AT_INGESTION); + assert_eq!(child(&timed).lifetime, KEPT_ACROSS); } /// The same holds for exact-accumulator state: a query-time build cannot @@ -1471,12 +1491,12 @@ mod tests { ); let mut assignment = MaterializationAssignment::default(); - assignment.set(&state, AT_INGESTION); + assignment.set(&state, at_ingestion()); let timed = apply_materialization_timings(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).materialization, AT_INGESTION); + assert_eq!(child(&timed).lifetime, KEPT_ACROSS); } /// A root stored at ingestion time is valid: the query reads the stored @@ -1486,27 +1506,27 @@ mod tests { fn a_root_may_be_stored_at_ingestion_time() { let root = max(scan()); let mut assignment = MaterializationAssignment::default(); - assignment.set(&root, AT_INGESTION); + assignment.set(&root, at_ingestion()); let timed = apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); - assert_eq!(exported(&timed, "Aggregate"), AT_INGESTION); + assert_eq!(exported(&timed, "Aggregate"), KEPT_ACROSS); let state = agg(scan(), exact_sum()); let root = finalize(Rc::clone(&state)); let mut assignment = MaterializationAssignment::default(); - assignment.set(&state, AT_INGESTION); - assignment.set(&root, AT_INGESTION); + assignment.set(&state, at_ingestion()); + assignment.set(&root, at_ingestion()); let timed = apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); - assert_eq!(exported(&timed, "FinalizeExactAccumulator"), AT_INGESTION); + assert_eq!(exported(&timed, "FinalizeExactAccumulator"), KEPT_ACROSS); let mut assignment = MaterializationAssignment::default(); let root = placed_at_ingestion(max(scan())); - assignment.set(&root, Materialization::NotMaterialized); + assignment.set(&root, None); assert_eq!( apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) .err(), diff --git a/crates/types/src/ir/schema/schema_support.rs b/crates/types/src/ir/schema/schema_support.rs index 913ab8728..820dd29bf 100644 --- a/crates/types/src/ir/schema/schema_support.rs +++ b/crates/types/src/ir/schema/schema_support.rs @@ -93,7 +93,7 @@ pub fn with_promql_series_identity( let mut rebuilt = OperatorNode::new(operator).map_err(|e| e.to_string())?; rebuilt.guarantee = node.guarantee.clone(); rebuilt.timing = node.timing; - rebuilt.materialization = node.materialization; + rebuilt.lifetime = node.lifetime; let rebuilt = Rc::new(rebuilt); cache.insert(Rc::as_ptr(node), Rc::clone(&rebuilt)); Ok(rebuilt) diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index b6e8c0157..e219b78f5 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -12,8 +12,8 @@ //! - [`workload`] — the planner inputs (#509): the query and data //! workloads and the parsed workload the query-language frontends produce //! ([`workload::parsed_workload`]). -//! - [`physical`] — Stage 2 decision data: the materialization of a -//! sub-DAG ([`physical::Materialization`]). +//! - [`physical`] — Stage 2 decision data: the physical properties of a +//! candidate ([`physical::PhysicalProperties`]: timing and lifetime). //! - [`stages`] — the types one planning stage hands the next: the Stage 1 //! → Stage 2 memo of groups and implementation candidates //! ([`stages::LogicalASAPMemoCandidates`]) and the Stage 2 → Stage 3 diff --git a/crates/types/src/physical/materialization.rs b/crates/types/src/physical/materialization.rs deleted file mode 100644 index e30e192b3..000000000 --- a/crates/types/src/physical/materialization.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! The materialization option of each sub-DAG (#509 §Materialization), the -//! Stage 2 decision a node's execution timing -//! ([`crate::ir::properties::ExecutionTiming`]) is derived -//! from. - -use crate::ir::properties::ExecutionTiming; - -/// Where a materialized output is stored (#509 §Materialization). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] -pub enum Medium { - Memory, - Disk, -} - -/// The materialization option of one sub-DAG (#509 §Materialization, -/// Algorithm 3): whether its output is stored across query executions, and -/// whether it is computed at ingestion time or at query time. -#[derive( - Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, -)] -pub enum Materialization { - /// Runs at query time for each execution; its output is discarded. - #[default] - NotMaterialized, - /// Runs as data arrives; its output is stored until a query reads it. - MatAtIngestion(Medium), - /// Runs when a query first needs it; its output is reused by the other - /// queries of the same evaluation and discarded after it. - MatAtQuery(Medium), - /// Runs at query time and keeps its output across evaluations: a - /// tumbling-window chain whose readers evaluate together every tumbling window - /// width builds its newest tumbling window at each evaluation and keeps the older - /// ones for the next (#509 Example 4's B3). Offered only when the - /// deployment keeps query-time results. - MatAtQueryKeptAcrossEvaluations(Medium), -} - -impl Materialization { - /// When the sub-DAG runs: only `MatAtIngestion` runs at ingestion time. - pub fn timing(self) -> ExecutionTiming { - match self { - Self::MatAtIngestion(_) => ExecutionTiming::IngestionTime, - Self::NotMaterialized - | Self::MatAtQuery(_) - | Self::MatAtQueryKeptAcrossEvaluations(_) => ExecutionTiming::QueryTime, - } - } - - /// Whether a node of this materialization is a materialized view: its - /// output is kept across evaluations. - pub(crate) fn is_materialized_view(self) -> bool { - matches!( - self, - Self::MatAtIngestion(_) | Self::MatAtQueryKeptAcrossEvaluations(_) - ) - } -} diff --git a/crates/types/src/physical/mod.rs b/crates/types/src/physical/mod.rs index bf10811ac..932f6e550 100644 --- a/crates/types/src/physical/mod.rs +++ b/crates/types/src/physical/mod.rs @@ -1,11 +1,11 @@ -//! #509 Stage 2 decision data: the materialization of each sub-DAG. +//! #509 Stage 2 decision data: the physical properties of each candidate. //! -//! - [`materialization`] — whether a sub-DAG's output is stored and when it -//! is computed ([`Materialization`], [`Medium`]). +//! - [`properties`] — when a candidate runs and how long its output lives +//! ([`PhysicalProperties`], [`Lifetime`], [`Medium`]). //! - [`workload_plan`] — one evaluated assignment rebuilt as a physical DAG //! ([`PhysicalWorkloadPlan`]). -pub mod materialization; +pub mod properties; pub mod workload_plan; -pub use materialization::{Materialization, Medium}; +pub use properties::{InvalidPhysicalProperties, Lifetime, Medium, PhysicalProperties}; pub use workload_plan::PhysicalWorkloadPlan; diff --git a/crates/types/src/physical/properties.rs b/crates/types/src/physical/properties.rs new file mode 100644 index 000000000..96ef56d09 --- /dev/null +++ b/crates/types/src/physical/properties.rs @@ -0,0 +1,133 @@ +//! A physical candidate's physical properties (#1200): when it runs +//! ([`ExecutionTiming`]) and how long its output lives ([`Lifetime`]). +//! +//! | timing | lifetime | how it runs | +//! |---|---|---| +//! | query | `None` | in each evaluation that reads it; discarded after its reader | +//! | query | `OneEvaluation` | once per evaluation; its readers in that evaluation share it | +//! | query | `AcrossEvaluations` | at query time, kept for later evaluations (a tumbling-window chain that builds its newest window each evaluation) | +//! | ingestion | `None` | as data arrives, inside the ingestion work that reads it | +//! | ingestion | `AcrossEvaluations` | as data arrives; kept until a query reads it | +//! | ingestion | `OneEvaluation` | invalid: there is no evaluation at ingestion time | + +use crate::ir::properties::ExecutionTiming; + +/// Where a kept output is stored. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +pub enum Medium { + Memory, + Disk, +} + +/// How long a node's output lives. Only a kept output has a medium. +#[derive( + Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, +)] +pub enum Lifetime { + /// Discarded after its reader's execution completes. + #[default] + None, + /// Kept until every reader within one evaluation finishes. + OneEvaluation(Medium), + /// Kept across evaluations, so later evaluations reuse it. + AcrossEvaluations(Medium), +} + +impl Lifetime { + /// Whether the output outlives its reader: `OneEvaluation` or + /// `AcrossEvaluations`. + pub fn is_kept(self) -> bool { + self != Self::None + } +} + +/// A timing and a lifetime that cannot go together. +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum InvalidPhysicalProperties { + #[error("an ingestion-time output cannot be kept for one evaluation: there is no evaluation at ingestion time")] + OneEvaluationAtIngestion, +} + +/// When a candidate runs and how long its output lives: one of the valid +/// rows of the table in this module's documentation. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)] +pub struct PhysicalProperties { + timing: ExecutionTiming, + lifetime: Lifetime, +} + +impl PhysicalProperties { + /// The properties `timing` and `lifetime`, unless they cannot go together. + pub fn new( + timing: ExecutionTiming, + lifetime: Lifetime, + ) -> Result { + match (timing, lifetime) { + (ExecutionTiming::IngestionTime, Lifetime::OneEvaluation(_)) => { + Err(InvalidPhysicalProperties::OneEvaluationAtIngestion) + } + _ => Ok(Self { timing, lifetime }), + } + } + + pub fn timing(self) -> ExecutionTiming { + self.timing + } + + pub fn lifetime(self) -> Lifetime { + self.lifetime + } + + /// Whether a reader running at `reader` may read this output: one at the + /// same timing, or a query-time reader of an ingestion-time output kept + /// until a query reads it. + pub fn readable_at(self, reader: ExecutionTiming) -> bool { + reader == self.timing + || (reader == ExecutionTiming::QueryTime + && self.timing == ExecutionTiming::IngestionTime + && matches!(self.lifetime, Lifetime::AcrossEvaluations(_))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn one_evaluation_at_ingestion_is_invalid() { + assert_eq!( + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::OneEvaluation(Medium::Memory) + ), + Err(InvalidPhysicalProperties::OneEvaluationAtIngestion) + ); + } + + #[test] + fn every_other_pair_is_valid() { + for timing in [ExecutionTiming::QueryTime, ExecutionTiming::IngestionTime] { + for lifetime in [ + Lifetime::None, + Lifetime::OneEvaluation(Medium::Memory), + Lifetime::AcrossEvaluations(Medium::Disk), + ] { + let valid = !(timing == ExecutionTiming::IngestionTime + && matches!(lifetime, Lifetime::OneEvaluation(_))); + assert_eq!(PhysicalProperties::new(timing, lifetime).is_ok(), valid); + } + } + } + + #[test] + fn a_query_time_reader_reads_only_a_kept_ingestion_output() { + let at = |timing, lifetime| PhysicalProperties::new(timing, lifetime).unwrap(); + let query = ExecutionTiming::QueryTime; + let ingestion = ExecutionTiming::IngestionTime; + assert!(at(ingestion, Lifetime::AcrossEvaluations(Medium::Memory)).readable_at(query)); + assert!(!at(ingestion, Lifetime::None).readable_at(query)); + assert!(at(ingestion, Lifetime::None).readable_at(ingestion)); + assert!(!at(query, Lifetime::OneEvaluation(Medium::Memory)).readable_at(ingestion)); + assert!(at(query, Lifetime::AcrossEvaluations(Medium::Memory)).readable_at(query)); + } +} diff --git a/crates/types/src/physical/workload_plan.rs b/crates/types/src/physical/workload_plan.rs index 47412bd9b..42d938810 100644 --- a/crates/types/src/physical/workload_plan.rs +++ b/crates/types/src/physical/workload_plan.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use crate::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; use crate::ir::QueryRoot; -use super::Materialization; +use super::Lifetime; /// One CandidatePhysicalASAPDAG (Stage 2 output), derived from exactly one /// CandidateLogicalASAPDAG (Stage 1 output). It holds planning data only; @@ -19,12 +19,13 @@ pub struct PhysicalWorkloadPlan { /// exports. pub roots: Vec, pub dag: PhysicalASAPDAG, - /// Its materialization assignment: the option chosen for each summary + /// Its materialization assignment: the lifetime chosen for each summary /// build (`SummaryAgg` or `SummaryTumblingWindowChain`) of `dag`, by node id, including - /// the builds left `NotMaterialized`, and each other node materialized + /// the builds not kept (`Lifetime::None`), and each other node kept /// (a shared node built once per evaluation). A build one query reads - /// at ingestion time and another at query time appears once per copy. - pub materialization: BTreeMap, + /// at ingestion time and another at query time appears once per copy; + /// each copy's timing is its `dag` node's. + pub lifetime: BTreeMap, } impl PhysicalWorkloadPlan { @@ -32,8 +33,6 @@ impl PhysicalWorkloadPlan { /// non-summary node built once per evaluation. #[cfg(any(test, feature = "test-support"))] pub fn materializes_any(&self) -> bool { - self.materialization - .values() - .any(|m| *m != Materialization::NotMaterialized) + self.lifetime.values().any(|lifetime| lifetime.is_kept()) } } diff --git a/crates/types/src/stages/physical/memo_candidates.rs b/crates/types/src/stages/physical/memo_candidates.rs index 1d500fc27..3075467cb 100644 --- a/crates/types/src/stages/physical/memo_candidates.rs +++ b/crates/types/src/stages/physical/memo_candidates.rs @@ -1,14 +1,13 @@ //! Stage 2's output: every operator node of every implementation candidate, -//! each with the timings and materializations Stage 2 allows, and which +//! each with the physical properties (timing, lifetime) Stage 2 allows, and which //! candidates may produce each input. Stage 3 selects among them; Stage 2 //! prices nothing. use std::rc::Rc; use super::graph::{PhysicalCandidateId, ReaderConstraint}; use super::producers::ProducerCandidates; -use crate::ir::properties::ExecutionTiming; use crate::ir::{OperatorNode, QueryRoot}; -use crate::physical::Materialization; +use crate::physical::PhysicalProperties; use crate::stages::{MemoGroupId, PrunedCandidate}; /// One implementation candidate: index `index` in group `group`'s @@ -25,7 +24,7 @@ pub struct CandidateForMemoGroupId { pub struct OperatorNodeOfCandidateForMemoGroupId(pub usize); /// One operator node of one or more candidates for a memo group, before -/// Stage 2 chose its timing and materialization. +/// Stage 2 chose its physical properties. #[derive(Debug, Clone)] pub struct OperatorNodeOfCandidateForMemoGroup { /// Every candidate of the group this node can implement, ascending: @@ -59,18 +58,16 @@ impl OperatorNodeOfCandidateForMemoGroup { } } -/// One operator node with one timing and materialization: what Stage 3 +/// One operator node with one timing and lifetime: what Stage 3 /// selects. A selection may run it more than once, each run a node of the /// [`DagOfSelectedCandidates`](super::DagOfSelectedCandidates). #[derive(Debug, Clone)] pub struct PhysicalCandidate { /// The operator node it runs. pub operator_node: OperatorNodeOfCandidateForMemoGroupId, - /// When it runs. A node that is not materialized under an ingestion-time - /// build still runs at ingestion time, so both are kept. - pub timing: ExecutionTiming, - /// Whether and where its result is kept. - pub materialization: Materialization, + /// When it runs and how long its result lives. A node that is not kept + /// under an ingestion-time build still runs at ingestion time. + pub properties: PhysicalProperties, /// Per input of its operator node (in `map_children` order), the /// candidates that may produce it. Depends on its timing. pub producer_candidates_per_input: Vec, @@ -80,7 +77,7 @@ pub struct PhysicalCandidate { pub may_produce_query_output: bool, /// One entry per workload query: whether this tumbling-window chain may be kept /// across evaluations when that query is its only reader. Filled only - /// for a `MatAtQueryKeptAcrossEvaluations(Memory)` tumbling-window chain in a + /// for a query-time tumbling-window chain kept `AcrossEvaluations(Memory)` in a /// deployment that keeps query-time results; empty otherwise. pub may_keep_across_evaluations_per_sole_reader_query: Vec, } @@ -89,24 +86,23 @@ pub struct PhysicalCandidate { /// candidates are renumbered after pruning, so a pruned one has no /// [`PhysicalCandidateId`]. Unique among a [`PhysicalASAPMemoCandidates`]' /// `pruned_candidates`: an operator node has at most one candidate per -/// timing and materialization. +/// physical properties. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PhysicalCandidateKey { /// Its operator node: an index into the output's /// `operator_nodes_of_candidates_for_memo_groups`, which pruning keeps /// whole. pub operator_node: OperatorNodeOfCandidateForMemoGroupId, - pub timing: ExecutionTiming, - pub materialization: Materialization, + pub properties: PhysicalProperties, } /// Stage 2's output, which Stage 3 selects from. #[derive(Debug, Clone)] pub struct PhysicalASAPMemoCandidates { /// One per operator node of an implementation, before Stage 2 chose its - /// timing and materialization. + /// timing and lifetime. pub operator_nodes_of_candidates_for_memo_groups: Vec, - /// One per (operator node, timing, materialization): what Stage 3 + /// One per (operator node, timing, lifetime): what Stage 3 /// selects. Indexed by [`PhysicalCandidateId`]. pub candidates: Vec, /// Each query's root over groups, by index in the workload, passed diff --git a/crates/types/src/stages/physical/producers.rs b/crates/types/src/stages/physical/producers.rs index 0e7547434..ed231e3cc 100644 --- a/crates/types/src/stages/physical/producers.rs +++ b/crates/types/src/stages/physical/producers.rs @@ -120,7 +120,7 @@ mod tests { }; use crate::ir::properties::ExecutionTiming; use crate::ir::QueryRoot; - use crate::physical::Materialization; + use crate::physical::{Lifetime, PhysicalProperties}; use crate::stages::MemoGroupId; let mut interner = ProducerSetInterner::default(); let choices = interner.intern(vec![PhysicalCandidateId(0), PhysicalCandidateId(1)]); @@ -147,8 +147,8 @@ mod tests { (0..3) .map(|id| PhysicalCandidate { operator_node: OperatorNodeOfCandidateForMemoGroupId(id), - timing: ExecutionTiming::QueryTime, - materialization: Materialization::NotMaterialized, + properties: PhysicalProperties::new(ExecutionTiming::QueryTime, Lifetime::None) + .unwrap(), producer_candidates_per_input: if id == 2 { vec![choices.clone(), choices.clone()] } else { diff --git a/crates/types/src/stages/pruning.rs b/crates/types/src/stages/pruning.rs index f857460f4..42deb7432 100644 --- a/crates/types/src/stages/pruning.rs +++ b/crates/types/src/stages/pruning.rs @@ -86,7 +86,7 @@ pub enum PruneReason { /// candidates, once each candidate's allowed readers are applied. ReachesNoQueryOutput, /// Stage 2: it is shared within one query evaluation - /// (`MatAtQuery`), which needs at least two reading queries, and fewer + /// (`OneEvaluation`), which needs at least two reading queries, and fewer /// queries can reach it. TooFewQueryReaders, /// Stage 3: the candidate it names, in the same memo group with the diff --git a/crates/types/src/stages/realizer.rs b/crates/types/src/stages/realizer.rs index 8c2ff17d6..ab1258f16 100644 --- a/crates/types/src/stages/realizer.rs +++ b/crates/types/src/stages/realizer.rs @@ -38,7 +38,7 @@ impl From<&str> for PhysicalCandidateError { #[derive(Debug, Clone)] pub struct RealizedPlan { /// The selection rebuilt as one physical plan, one operator node per - /// selected node, each with its candidate's timing and materialization. + /// selected node, each with its candidate's timing and lifetime. pub plan: PhysicalWorkloadPlan, /// For each tumbling-window chain of `plan` kept beyond one evaluation /// (maintained at ingestion time, or built at query time and kept @@ -68,7 +68,7 @@ pub struct RealizedPlan { /// recomposed, and every output contract (result kind and schema) met; a /// realized assignment also passes Stage 2's timing and dependency rules /// and the physical DAG validator, with every node keeping its -/// candidate's timing and materialization. +/// candidate's timing and lifetime. /// /// It checks structure and execution legality only. It does not check cost, /// and it does not check accuracy targets: Stage 3 does both. diff --git a/crates/types/src/test_support.rs b/crates/types/src/test_support.rs index d267ee3eb..6ce4619a3 100644 --- a/crates/types/src/test_support.rs +++ b/crates/types/src/test_support.rs @@ -14,7 +14,6 @@ use crate::ir::properties::ExecutionDataStateError; use crate::ir::schema::Schema; use crate::ir::{ASAPOp, NonASAPOp}; use crate::ir::{OperatorNode, SchemaDerivationError}; -use crate::physical::Materialization; /// `SummaryCoverage::definition_id`. pub fn definition_id(coverage: &SummaryCoverage) -> String { @@ -73,8 +72,3 @@ pub fn timed<'a>( pub fn lookback_ms(window: &RawDataWindow) -> u64 { window.lookback_ms() } - -/// `Materialization::is_materialized_view`. -pub fn is_materialized_view(materialization: Materialization) -> bool { - materialization.is_materialized_view() -} diff --git a/crates/types/src/workload/bounds.rs b/crates/types/src/workload/bounds.rs index a50afb0ed..4b7a2713b 100644 --- a/crates/types/src/workload/bounds.rs +++ b/crates/types/src/workload/bounds.rs @@ -478,7 +478,7 @@ pub fn with_confirmed_weights_at( OperatorNode::with_schema(operator, node.schema.clone()) .with_guarantee(node.guarantee.clone()) .with_timing(node.timing) - .with_materialization(node.materialization), + .with_lifetime(node.lifetime), ) } else { Rc::clone(node) diff --git a/crates/types/tests/materialized_view.rs b/crates/types/tests/materialized_view.rs index 0576ca187..8a6de6150 100644 --- a/crates/types/tests/materialized_view.rs +++ b/crates/types/tests/materialized_view.rs @@ -15,6 +15,7 @@ use asap_types::ir::operator::TimeShift; use asap_types::ir::physical_export::{ compile_physical_asap_dag, compile_physical_asap_workload, PhysicalASAPDAG, }; +use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::{ DataType, Field, FieldDataType, GroupingStrategy, Schema, SketchAlgorithm, SketchKind, @@ -25,7 +26,7 @@ use asap_types::ir::{ MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, TimeRangeKind, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; /// A KLL of `m`'s values over `(T - shift - 1 min, T - shift]`. fn tumbling_window(scan: &Rc, shift_ms: i64) -> Rc { @@ -96,12 +97,20 @@ fn tumbling_windows_and_kept_merge() -> (PhysicalASAPDAG, usize) { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - Materialization::MatAtIngestion(Medium::Memory), + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), ); } assignment.set( &merge, - Materialization::MatAtQueryKeptAcrossEvaluations(Medium::Memory), + PhysicalProperties::new( + ExecutionTiming::QueryTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), ); let timed = apply_materialization_timings(&merge, &assignment, &mut NodeToTimedNodeCache::new()) @@ -233,7 +242,14 @@ fn three_chains_over_one_scan() -> (PhysicalASAPDAG, PhysicalASAPDAG) { let roots: Vec = chains .iter() .map(|chain| { - assignment.set(chain, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + chain, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); QueryRoot::Operator( OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryMerge { children: vec![Rc::clone(chain)], @@ -370,7 +386,11 @@ fn a_shifted_tumbling_window_has_its_own_phase() { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - Materialization::MatAtIngestion(Medium::Memory), + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), ); } let roots: Vec = tumbling_windows @@ -415,7 +435,14 @@ fn views_of_unbounded_windows_are_groups_of_their_own() { filter: None, })) .unwrap(); - assignment.set(&build, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + &build, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); QueryRoot::Operator(build) }) .collect(); @@ -445,7 +472,14 @@ fn a_view_reading_a_view_of_its_group_follows_it() { .unwrap(); let mut assignment = MaterializationAssignment::default(); for view in [&tumbling_window, &rollup] { - assignment.set(view, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + view, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); } let timed = apply_materialization_timings_to_roots( &[QueryRoot::Operator(Rc::clone(&rollup))], @@ -497,7 +531,14 @@ fn a_node_above_an_unexpanded_chain_has_the_window_of_its_tumbling_windows() { fn a_view_has_its_refresh_window_on_a_dag_without_edges() { let view = tumbling_window(&scan_m(), 15_000); let mut assignment = MaterializationAssignment::default(); - assignment.set(&view, Materialization::MatAtIngestion(Medium::Memory)); + assignment.set( + &view, + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); let timed = apply_materialization_timings(&view, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let mut dag = compile_physical_asap_dag(&timed).unwrap(); diff --git a/crates/types/tests/physical_export.rs b/crates/types/tests/physical_export.rs index e2f701ffb..b87d9499b 100644 --- a/crates/types/tests/physical_export.rs +++ b/crates/types/tests/physical_export.rs @@ -12,7 +12,7 @@ use asap_types::ir::{ apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; /// Scan(t) → SummaryAgg(sum by key) → FinalizeExactAccumulator, untimed. @@ -43,13 +43,16 @@ fn plan() -> Rc { .unwrap() } -const ON_DISK: Materialization = Materialization::MatAtIngestion(Medium::Disk); +const ON_DISK: Lifetime = Lifetime::AcrossEvaluations(Medium::Disk); -/// `plan()` timed with its summary `MatAtIngestion` on disk. +/// `plan()` timed with its summary kept at ingestion time on disk. fn timed_at_ingestion() -> Rc { let root = plan(); let mut assignment = MaterializationAssignment::default(); - assignment.set(root.children()[0], ON_DISK); + assignment.set( + root.children()[0], + PhysicalProperties::new(ExecutionTiming::IngestionTime, ON_DISK).ok(), + ); apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap() } @@ -70,15 +73,8 @@ fn timed_plan_exports_with_timing() { ExecutionTiming::QueryTime ] ); - let materializations: Vec<_> = dag.nodes.iter().map(|n| n.materialization).collect(); - assert_eq!( - materializations, - vec![ - Materialization::NotMaterialized, - ON_DISK, - Materialization::NotMaterialized - ] - ); + let lifetimes: Vec<_> = dag.nodes.iter().map(|n| n.lifetime).collect(); + assert_eq!(lifetimes, vec![Lifetime::None, ON_DISK, Lifetime::None]); // Timing keeps what the summary covers. assert!(timed.children()[0].coverage().is_some()); @@ -99,24 +95,31 @@ fn query_time_input_to_ingestion_is_rejected() { )); } -/// A summary's timing must be the one its materialization implies: the -/// deployment cannot run a `MatAtIngestion` state at query time. +/// A node's timing and lifetime must go together: an ingestion-time output +/// cannot be kept for one evaluation, and a summary build that is not kept +/// runs at query time. #[test] -fn materialization_inconsistent_with_timing_is_rejected() { +fn invalid_physical_properties_are_rejected() { let mut dag = compile_physical_asap_dag(&timed_at_ingestion()).unwrap(); - dag.nodes[1].output_state.timing = ExecutionTiming::QueryTime; - *dag.edges[1].data_state_mut() = dag.nodes[1].output_state; + dag.nodes[1].lifetime = Lifetime::OneEvaluation(Medium::Disk); assert_eq!( dag.validate(), - Err( - PhysicalASAPDAGValidationError::MaterializationTimingMismatch { - node: 1, - timing: ExecutionTiming::QueryTime, - materialization: ON_DISK, - } - ) + Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { + node: 1, + timing: ExecutionTiming::IngestionTime, + lifetime: Lifetime::OneEvaluation(Medium::Disk), + }) + ); + dag.nodes[1].lifetime = Lifetime::None; + assert_eq!( + dag.validate(), + Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { + node: 1, + timing: ExecutionTiming::IngestionTime, + lifetime: Lifetime::None, + }) ); - dag.nodes[1].materialization = Materialization::MatAtQuery(Medium::Disk); + dag.nodes[1].lifetime = ON_DISK; dag.validate().unwrap(); } @@ -187,7 +190,7 @@ fn scalar_roots_export_in_batch_order_and_reference_nodes() { scalar_only.roots.clear(); scalar_only.validate().unwrap(); let valid_scalar_only = scalar_only.clone(); - // Materialization is checked on the nodes a scalar reads, too. + // Physical properties are checked on the nodes a scalar reads, too. let state = scalar_only .nodes .iter() @@ -200,16 +203,15 @@ fn scalar_roots_export_in_batch_order_and_reference_nodes() { ) }) .unwrap(); - scalar_only.nodes[state].materialization = ON_DISK; + scalar_only.nodes[state].output_state.timing = ExecutionTiming::IngestionTime; + scalar_only.nodes[state].lifetime = Lifetime::OneEvaluation(Medium::Disk); assert_eq!( scalar_only.validate(), - Err( - PhysicalASAPDAGValidationError::MaterializationTimingMismatch { - node: scalar_only.nodes[state].id, - timing: ExecutionTiming::QueryTime, - materialization: ON_DISK, - } - ) + Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { + node: scalar_only.nodes[state].id, + timing: ExecutionTiming::IngestionTime, + lifetime: Lifetime::OneEvaluation(Medium::Disk), + }) ); let mut missing = dag.clone(); @@ -390,8 +392,13 @@ fn exports_summary_over_summary_as_typed_precompute_edges() { })) .unwrap(); let mut cache = NodeToTimedNodeCache::new(); - let at_ingestion = - MaterializationAssignment::with_default(Materialization::MatAtIngestion(Medium::Memory)); + let at_ingestion = MaterializationAssignment::with_default( + PhysicalProperties::new( + ExecutionTiming::IngestionTime, + Lifetime::AcrossEvaluations(Medium::Memory), + ) + .ok(), + ); let timed = apply_materialization_timings(&root, &at_ingestion, &mut cache).unwrap(); let compiled = compile_physical_asap_dag_with_node_ids(&timed).unwrap(); assert_eq!(compiled.node_ids.node_id(&timed), Some(3)); @@ -456,13 +463,13 @@ fn retention_is_only_on_materialized_views_and_query_time_scans() { let view = dag .nodes .iter() - .position(|node| asap_types::test_support::is_materialized_view(node.materialization)) + .position(|node| matches!(node.lifetime, Lifetime::AcrossEvaluations(_))) .expect("a node built at ingestion"); let other = dag .nodes .iter() .position(|node| { - !asap_types::test_support::is_materialized_view(node.materialization) + !matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) && node.output_state.timing == ExecutionTiming::IngestionTime }) .expect("an ingestion-time node that is not a view"); @@ -712,7 +719,7 @@ fn high_fan_in_edges_preserve_multiplicity_without_order_dependence() { schema: schema.clone(), }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Materialization::NotMaterialized, + lifetime: Lifetime::None, output_schema: schema.clone(), guarantee: None, retention_ms: None, @@ -725,7 +732,7 @@ fn high_fan_in_edges_preserve_multiplicity_without_order_dependence() { children: inputs.clone(), }), output_state: ExecutionDataState::QUERY_ROWS, - materialization: Materialization::NotMaterialized, + lifetime: Lifetime::None, output_schema: schema.clone(), guarantee: None, retention_ms: None, diff --git a/crates/types/tests/schema_rebuilding.rs b/crates/types/tests/schema_rebuilding.rs index 6e61144a8..71663330c 100644 --- a/crates/types/tests/schema_rebuilding.rs +++ b/crates/types/tests/schema_rebuilding.rs @@ -333,7 +333,7 @@ fn a_current_series_population_matches_only_its_selectors_lookback() { } /// Population timing is a materialization choice: the population follows its -/// assignment (`NotMaterialized` by default), while its evaluation always +/// assignment (not kept by default), while its evaluation always /// runs at query time. #[test] fn population_timing_follows_its_materialization() { @@ -342,7 +342,7 @@ fn population_timing_follows_its_materialization() { use asap_types::ir::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, }; - use asap_types::physical::{Materialization, Medium}; + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; let candidate = current_series_topk(); let Some(ASAPOp::EvaluatePopulation { child: population, .. @@ -350,14 +350,17 @@ fn population_timing_follows_its_materialization() { else { unreachable!() }; - let on_disk = Materialization::MatAtIngestion(Medium::Disk); + let on_disk = Lifetime::AcrossEvaluations(Medium::Disk); let mut at_ingestion = MaterializationAssignment::default(); - at_ingestion.set(population, on_disk); - for (assignment, timing, materialization) in [ + at_ingestion.set( + population, + PhysicalProperties::new(IngestionTime, on_disk).ok(), + ); + for (assignment, timing, lifetime) in [ ( MaterializationAssignment::default(), QueryTime, - Materialization::NotMaterialized, + Lifetime::None, ), (at_ingestion, IngestionTime, on_disk), ] { @@ -372,7 +375,7 @@ fn population_timing_follows_its_materialization() { unreachable!() }; assert_eq!(population.output_state.timing, timing); - assert_eq!(population.materialization, materialization); + assert_eq!(population.lifetime, lifetime); assert_eq!(evaluation.output_state.timing, QueryTime); } let mut evaluation_at_ingestion = (*candidate).clone(); diff --git a/crates/types/tests/summary_merge_structure.rs b/crates/types/tests/summary_merge_structure.rs index b76ad5cc7..cc382cb28 100644 --- a/crates/types/tests/summary_merge_structure.rs +++ b/crates/types/tests/summary_merge_structure.rs @@ -13,7 +13,7 @@ use asap_types::ir::{ apply_materialization_timings, ASAPOp, ExprSemantics, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, Predicate, ScalarExpr, }; -use asap_types::physical::{Materialization, Medium}; +use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; /// KLL over `value` for one `region`, so states of different regions are /// disjoint. @@ -720,7 +720,8 @@ fn summary_merge_timing() { timings(&MaterializationAssignment::default()), (QueryTime, vec![QueryTime, QueryTime]) ); - let at_ingestion = Materialization::MatAtIngestion(Medium::Memory); + let at_ingestion = + PhysicalProperties::new(IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory)).ok(); let mut stored_tumbling_windows = MaterializationAssignment::default(); for tumbling_window in &tumbling_windows { stored_tumbling_windows.set(tumbling_window, at_ingestion); diff --git a/crates/types/tests/tumbling_window_chain.rs b/crates/types/tests/tumbling_window_chain.rs index b37d77385..76173657f 100644 --- a/crates/types/tests/tumbling_window_chain.rs +++ b/crates/types/tests/tumbling_window_chain.rs @@ -174,7 +174,7 @@ fn expansion_merges_the_tumbling_windows() { assert!(expand_tumbling_window_chains(&chain).is_err()); } -/// Expanding a timed chain carries its timing and materialization onto its +/// Expanding a timed chain carries its timing and lifetime onto its /// tumbling windows: a chain materialized at ingestion time expands into tumbling windows each /// built and stored at ingestion time, over ranges and shifts that run at /// ingestion time too, while the merge reading them stays at query time. @@ -185,11 +185,11 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { use asap_types::ir::{ apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, }; - use asap_types::physical::{Materialization, Medium}; - let at_ingestion = Materialization::MatAtIngestion(Medium::Memory); - for (materialization, timing) in [ - (at_ingestion, ExecutionTiming::IngestionTime), - (Materialization::NotMaterialized, ExecutionTiming::QueryTime), + use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; + let kept_across = Lifetime::AcrossEvaluations(Medium::Memory); + for (lifetime, timing) in [ + (kept_across, ExecutionTiming::IngestionTime), + (Lifetime::None, ExecutionTiming::QueryTime), ] { let chain = chain(shifted(scan(), MINUTE as i64)); let estimate = OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryEstimate { @@ -198,7 +198,12 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { })) .unwrap(); let mut assignment = MaterializationAssignment::default(); - assignment.set(&chain, materialization); + assignment.set( + &chain, + lifetime + .is_kept() + .then(|| PhysicalProperties::new(timing, lifetime).unwrap()), + ); let timed = apply_materialization_timings(&estimate, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -207,11 +212,11 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { assert_eq!(merged.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(merged.children().len(), 5); for tumbling_window in merged.children() { - assert_eq!(tumbling_window.timing, Some(timing), "{materialization:?}"); - assert_eq!(tumbling_window.materialization, materialization); + assert_eq!(tumbling_window.timing, Some(timing), "{lifetime:?}"); + assert_eq!(tumbling_window.lifetime, lifetime); for below in OperatorNode::reachable(tumbling_window).iter().skip(1) { assert_eq!(below.timing, Some(timing), "{}", below.operator.kind_name()); - assert_eq!(below.materialization, Materialization::NotMaterialized); + assert_eq!(below.lifetime, Lifetime::None); } } } diff --git a/docs/design_docs/architecture/physical-plan-integration.md b/docs/design_docs/architecture/physical-plan-integration.md index a9961b710..e33c876ad 100644 --- a/docs/design_docs/architecture/physical-plan-integration.md +++ b/docs/design_docs/architecture/physical-plan-integration.md @@ -462,8 +462,8 @@ finalized before row operators consume them. None of these operations proves candidate completeness; that evidence belongs to the semi-join's pruning step. The logical DAG carries no execution layout: `apply_materialization_timings` -writes each node's timing and materialization from a -`MaterializationAssignment` before export (every sub-DAG `NotMaterialized` by -default, so all query time). The exported DAG carries both, and the deployment +writes each node's timing and lifetime from a +`MaterializationAssignment` before export (no sub-DAG kept by default, so all +query time). The exported DAG carries both, and the deployment executes it as given; this is not a claim that every deployment has implemented every placement. diff --git a/docs/design_docs/architecture/planner-runtime-contract.md b/docs/design_docs/architecture/planner-runtime-contract.md index 69813bc5f..8b5d16321 100644 --- a/docs/design_docs/architecture/planner-runtime-contract.md +++ b/docs/design_docs/architecture/planner-runtime-contract.md @@ -14,7 +14,7 @@ execution remain downstream. The | Layer | Owner | Examples | |---|---|---| | Logical candidate semantics | ASAPPlanner | Query rewrite; summary family and parameters; grouping; accuracy guarantees when established. | -| Summary materialization and realization selection | ASAPPlanner Stage 2 materialization (#509) | `NotMaterialized`, `MatAtIngestion(medium)` or `MatAtQuery(medium)` per sub-DAG, and how long a stored output is kept; direct build or incremental update; window implementations compared using provider evidence. | +| Summary materialization and realization selection | ASAPPlanner Stage 2 materialization (#509) | a timing and a lifetime per sub-DAG (`None`, `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and how much a kept output retains; direct build or incremental update; window implementations compared using provider evidence. | | Concrete implementation and deployment | ASAPQuery-backend and its workload optimizer | Library and data-structure implementation, exact tumbling-window layout, placement, sharding, storage, transmission, materialization IDs, executor configuration, and workload-wide assignment. | ASAPCollector and the ASAPQuery data plane execute the compiled downstream diff --git a/docs/design_docs/concepts/glossary.md b/docs/design_docs/concepts/glossary.md index c27400a31..376a0736e 100644 --- a/docs/design_docs/concepts/glossary.md +++ b/docs/design_docs/concepts/glossary.md @@ -38,7 +38,7 @@ A concrete execution and deployment choice: runtime topology of data lifecycle s ## Materialized view -A node of the physical DAG whose output is kept across evaluations (`MatAtIngestion` or `MatAtQueryKeptAcrossEvaluations`), with how long it is kept (`retention_ms` on the node). A `MatAtQuery` node is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. +A node of the physical DAG whose output is kept across evaluations (lifetime `AcrossEvaluations`, at ingestion time or at query time), with how long it is kept (`retention_ms` on the node). A node kept for `OneEvaluation` is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. ## Raw data sample diff --git a/docs/design_docs/concepts/post-asap-ir.md b/docs/design_docs/concepts/post-asap-ir.md index ea9d9e57b..3e4c5bcda 100644 --- a/docs/design_docs/concepts/post-asap-ir.md +++ b/docs/design_docs/concepts/post-asap-ir.md @@ -111,39 +111,42 @@ not definitions of the operator. The logical DAG carries no timing: `OperatorNode::timing` is `None` on every front-end node and every candidate, and `map_children` clears it. Materialization ([#509 §Materialization](../proposals/planner-layering.md#materialization)) -gives each sub-DAG one of three options: `NotMaterialized`, -`MatAtIngestion(medium)` or `MatAtQuery(medium)`, with `Medium::Memory` or -`Medium::Disk`. A -[`MaterializationAssignment`](../../../crates/types/src/ir/properties/timing.rs) records -the option per sub-DAG, named by the node whose output would be stored. Any -node may be named: a summary state, a population, or, as in #509 Example 4, -the tumbling windows a query reads. `set(node, materialization)` assigns -one, and every other sub-DAG is `NotMaterialized`. Choosing the options is -Stage 2's job (#604); until then the planner materializes nothing. +decides, for each sub-DAG, whether its output is kept, and if so with which +[`PhysicalProperties`](../../../crates/types/src/physical/properties.rs): a +timing and a `Lifetime` (#1200). The lifetime is `None` (discarded after its +reader), `OneEvaluation(medium)` (kept until every reader of one evaluation +finishes) or `AcrossEvaluations(medium)` (kept for later evaluations), with +`Medium::Memory` or `Medium::Disk`; an ingestion-time output cannot be kept +for `OneEvaluation`. A +[`MaterializationAssignment`](../../../crates/types/src/ir/properties/timing.rs) records, +per sub-DAG, the properties of its kept output, named by the node whose output +would be kept. Any node may be named: a summary state, a population, or, as in +#509 Example 4, the tumbling windows a query reads. `set(node, Some(properties))` +keeps one, `set(node, None)` keeps none, and every other sub-DAG is not kept. +Stage 2 chooses the assignment. `apply_materialization_timings(root, &assignment, &mut NodeToTimedNodeCache)` then writes a -timing and a materialization into every node, top-down: +timing and a lifetime into every node, top-down: - `SummaryEstimate` and `EvaluatePopulation` run at query time; -- a node assigned `MatAtIngestion` runs at ingestion time, and one assigned - `MatAtQuery` at query time; a `SummaryAgg` or `MaintainPopulation` that is - `NotMaterialized` runs at query time. Every node upstream of an - ingestion-time node also runs at ingestion time, so `MatAtIngestion` over - something that can only exist at query time (an evaluation, or a state - that is not `MatAtIngestion`) fails with +- a node assigned a kept output runs at that output's timing; a `SummaryAgg` + or `MaintainPopulation` that is not kept runs at query time. Every node + upstream of an ingestion-time node also runs at ingestion time, so a kept + ingestion-time output over something that can only exist at query time (an + evaluation, or a state not kept at ingestion time) fails with `ExecutionDataStateError::UpstreamNotAtIngestion` ("upstream of ingestion-time node not at ingestion time"); -- every other node is not stored and runs when its consumer runs: everything +- every other node is not kept and runs when its consumer runs: everything that feeds an ingestion-time node runs at ingestion time, everything above - an evaluation at query time. A query-time consumer reads a `MatAtIngestion` - node's stored output. + an evaluation at query time. A query-time consumer reads the stored output + of a node kept at ingestion time (`AcrossEvaluations`). A node whose timing a candidate builder fixed (the query-time `FinalizeExactAccumulator` read boundary of `finalize_query_candidate`) keeps it: an explicit assignment that agrees with that timing is kept, and one that needs the other timing fails with `ExecutionDataStateError::MaterializationConflictsWithFixedTiming`; an -explicit `MatAtIngestion` is never silently moved or dropped. A root may be -`MatAtIngestion`, and the query reads its stored output; a root of rows that +explicit kept output is never silently moved or dropped. A root may be kept +at ingestion time, and the query reads its stored output; a root of rows that runs at ingestion time without being stored there fails with `ExecutionDataStateError::UnstoredIngestionRoot`. @@ -152,16 +155,17 @@ The pass then validates every edge (rows or exact-accumulator state into a an `EvaluatePopulation`, no ingestion work reading a query-time value) and rejects a node reached from two consumers that need different timings; `split_shared_by_timing` copies such a sub-DAG for one side before the -assignment is applied. How long a materialized output is kept (retention) is -also Stage 2's decision and is not in the assignment. +assignment is applied. How much a kept output retains (retention) is decided +later and is not in the assignment. -`MaterializationAssignment::with_default(materialization)` gives every sub-DAG -that is not set explicitly `materialization` where the DAG allows it; a -`MatAtIngestion` default over a sub-DAG that can only run at query time leaves -that sub-DAG `NotMaterialized` instead of failing (the default applies to +`MaterializationAssignment::with_default(kept)` gives every sub-DAG that is +not set explicitly `kept` where the DAG allows it; an ingestion-time default +over a sub-DAG that can only run at query time leaves that sub-DAG not kept +instead of failing (the default applies to `SummaryAgg` and `MaintainPopulation` nodes). The test helpers `validate_at_ingestion` and `planned_data_state` (feature `test-support`) use it to check, at planning time and without keeping -anything, that a candidate stays valid when every sub-DAG is `MatAtIngestion`. +anything, that a candidate stays valid when every sub-DAG is kept at ingestion +time. ## Exported DAG @@ -193,12 +197,14 @@ children as edges and no embedded sub-DAGs: (`ExecutionDataStateError::UntimedNode`); it does not re-run data-state validation. -Each node also records its `materialization`, including the medium, so the -deployment knows which outputs to store and where; validation rejects a -`SummaryAgg` or `MaintainPopulation` whose timing differs from the one its -materialization implies, and any `MatAtIngestion` or `MatAtQuery` node at the -other timing. Ingestion work cannot depend on a future query result. The -deployment executes the plan as given and does not change its materialization +Each node also records its `lifetime`, including the medium, so the +deployment knows which outputs to keep, for how long and where; validation +rejects a timing and lifetime that cannot go together (an ingestion-time +output kept for `OneEvaluation`) and a `SummaryAgg` or `MaintainPopulation` +that is not kept outside query time +(`PhysicalASAPDAGValidationError::InvalidPhysicalProperties`). Ingestion +work cannot depend on a future query result. The +deployment executes the plan as given and does not change its lifetime or timing ([#509 Assumption 8](../proposals/planner-layering.md#assumptions)); it must separately check that it has an implementation and a valid data source for each placement. diff --git a/docs/design_docs/physical-planning-and-deployment.md b/docs/design_docs/physical-planning-and-deployment.md index cf597bf16..31f34d7a1 100644 --- a/docs/design_docs/physical-planning-and-deployment.md +++ b/docs/design_docs/physical-planning-and-deployment.md @@ -46,15 +46,14 @@ decided by a `MaterializationAssignment`, as the layer contract below states. 1. **Logical Post-ASAP** (`CandidateLogicalASAPDAGs`) decides what to compute: summary families, readouts and sharing. It does not decide placement; timing that a realization strategy writes while building a candidate is provisional. -2. **Materialization** (Stage 2, #509) chooses `NotMaterialized`, - `MatAtIngestion(medium)`, `MatAtQuery(medium)` or - `MatAtQueryKeptAcrossEvaluations(medium)` for each sub-DAG whose - output may be stored (a `SummaryAgg` or a `MaintainPopulation`) and records - it in a `MaterializationAssignment`. `apply_materialization_timings` writes - every node's `ExecutionTiming` and `Materialization`: a `MatAtIngestion` - state and all of its inputs run at ingestion time; readouts, other - consumers, and the other states run at query time. The default assignment - is `NotMaterialized` everywhere; `PlanOutput::physical_asap_dag` applies it +2. **Materialization** (Stage 2, #509) chooses, for each sub-DAG whose + output may be stored (a `SummaryAgg` or a `MaintainPopulation`), whether + it is kept and with which timing and `Lifetime` (`None`, + `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and records it in + a `MaterializationAssignment`. `apply_materialization_timings` writes every + node's `ExecutionTiming` and `Lifetime`: a state kept at ingestion time and + all of its inputs run at ingestion time; readouts, other consumers, and the + other states run at query time. The default assignment keeps nothing; `PlanOutput::physical_asap_dag` applies it only to nodes the optimization pass left untimed (a pass's own timing, such as Stage 3's ingestion-time tumbling windows, is kept). 3. **Physical compile** (executor) reads the plan's materialized views: each @@ -473,8 +472,8 @@ These derivations are methods on `PhysicalASAPDAG` in `asap-types`, so a runtime needs no dependency on the planner crate. A **materialized view** is a node whose output is kept across evaluations -(`MatAtIngestion` or `MatAtQueryKeptAcrossEvaluations`). A `MatAtQuery` node is -not a view: its output is discarded after one evaluation. Everything a runtime +(lifetime `AcrossEvaluations`, at ingestion or at query time). A node kept for +`OneEvaluation` is not a view: its output is discarded after one evaluation. Everything a runtime needs that the DAG determines is derived from the DAG, so the plan file has no second copy to keep consistent. Stage 3's selection report is returned beside the plan, not inside it. diff --git a/docs/design_docs/proposals/planner-layering.md b/docs/design_docs/proposals/planner-layering.md index cb93a3acb..298b1db0e 100644 --- a/docs/design_docs/proposals/planner-layering.md +++ b/docs/design_docs/proposals/planner-layering.md @@ -567,14 +567,14 @@ The sections below describe each stage. | 0. Frontends | nothing: a query that cannot be lowered fails planning with an error | — | — | | 1, Pass 1 | what the measure or the deployment cannot compute: `RequiresExact`, `NullableAvgInput`, `NoRelationalCountSketchRealization`, `UnsupportedByDeployment`, `QuantileOutsideUnitInterval`, `TopKHeapOverOneRowPerItem`; and, only when the deployment's accuracy model and evidence cannot accept an output without its guarantee, a summary no query reading it can use: `NoErrorBoundForQueryTarget` | `PerComputationLogicalMemoCandidates::pruned_candidates`, each on its aggregate's memo group | the way to compute the measure (`HowToComputeAggregateMeasure`) | | 1, Pass 2 | nothing: it only adds candidates | — | — | -| 2 | what cannot be implemented, built or kept: `PerEntityAggregateNotExecutable` (an exact per-entity `Aggregate` the executor has no kernel for), `RawDataNotRetained` (a query-time scan of raw data the deployment does not keep), `InputHasNoBuildableProducer`, `ReachesNoQueryOutput`, `TooFewQueryReaders` (shared within one evaluation with fewer than two reading queries) | `PhysicalASAPMemoCandidates::pruned_candidates`, each on its operator node's memo group | `PhysicalCandidateKey { operator_node, timing, materialization }` | +| 2 | what cannot be implemented, built or kept: `PerEntityAggregateNotExecutable` (an exact per-entity `Aggregate` the executor has no kernel for), `RawDataNotRetained` (a query-time scan of raw data the deployment does not keep), `InputHasNoBuildableProducer`, `ReachesNoQueryOutput`, `TooFewQueryReaders` (shared within one evaluation with fewer than two reading queries) | `PhysicalASAPMemoCandidates::pruned_candidates`, each on its operator node's memo group | `PhysicalCandidateKey { operator_node, properties }` | | 3 | valid candidates that lose, and the checks only a whole plan can make (accuracy, latency, cluster capacity) | its own `RejectionCause` | — | Stage 2's key names what a pruned candidate would have been, since kept candidates are renumbered after pruning and a pruned one has no `PhysicalCandidateId`. Stage 2 emits one candidate per operator node, -timing and materialization, and makes no copies of it, so (`operator_node`, -`timing`, `materialization`) is unique. Operator +timing and lifetime, and makes no copies of it, so (`operator_node`, +`properties`) is unique. Operator nodes are kept whole, so `operator_node` indexes the output's `operator_nodes_of_candidates_for_memo_groups`. Pass 1's accuracy pruning (`NoErrorBoundForQueryTarget`) runs inside Pass 1's entry, before the @@ -600,7 +600,7 @@ the memo path's entry points. | 1, Pass 1 | Logical roots; the deployment's supported summaries → the Pass 1 inventory, every computation's candidates (`PerComputationCandidates`, now Pass 1's crate-private working form) | Logical roots → `DagOfLogicalMemoGroups` (hash-consed `MemoGroup`s); with the Pass 1 inventory, less the summaries the deployment does not support and those no query reading them can use → `PerComputationLogicalMemoCandidates`: the `Memo` (each group's `CandidateForMemoGroup`s, with the accuracy-scoped sizes) and the pruned candidates (`PrunedCandidate`) | `generate_dag_of_logical_memo_groups`, `generate_per_computation_logical_memo_candidates` | | 1, Pass 2 | One Pass 1 choice per computation → that choice rewritten by each sharing rule, every subset of sharing choices (no longer in the code) | `Memo`; the entries' recurrence and range steps → the same memo with each rule's candidates added to the groups they implement | the memo rules (`pass2/memo/rules/`), `pass2::memo::window_candidates` | | 1, concrete summary-state groups | (part of Pass 2) | `Memo` → the memo with concrete summary-state groups: one group per shared size or tumbling-window layout that readers can read | `add_shared_summary_state_groups`, Pass 2's last step; the Pass 2 output is `LogicalASAPMemoCandidates` (`generate_logical_asap_memo_candidates`) | -| 2 | One whole-workload logical candidate; entries (recurrence, predictability), `DataWorkload`, query-time retention → its physical candidates, one per materialization assignment | `LogicalASAPMemoCandidates`; entries, `DataWorkload`, query-time and raw-data retention → `PhysicalASAPMemoCandidates`: every operator node of every candidate with each allowed timing and materialization (one physical candidate each, no copies), the producers of each input, reader constraints (each applied to every selected run of its candidate), and the pruned candidates (`PrunedCandidate`) | `generate_physical_asap_memo_candidates` (`asap_physical_asap_optimization`) | +| 2 | One whole-workload logical candidate; entries (recurrence, predictability), `DataWorkload`, query-time retention → its physical candidates, one per materialization assignment | `LogicalASAPMemoCandidates`; entries, `DataWorkload`, query-time and raw-data retention → `PhysicalASAPMemoCandidates`: every operator node of every candidate with each allowed timing and lifetime (one physical candidate each, no copies), the producers of each input, reader constraints (each applied to every selected run of its candidate), and the pruned candidates (`PrunedCandidate`) | `generate_physical_asap_memo_candidates` (`asap_physical_asap_optimization`) | | 3 | Every physical candidate; accuracy targets, accuracy model and evidence, cost model → one plan | `PhysicalASAPMemoCandidates`; entries, `DataWorkload`, `AccuracyCheckInputs`, `CostInputs`, Stage 2's realizer → `Selection`: the selected plan (`selected_dag`, a `DagOfSelectedCandidates`: one node per run of a candidate, so a candidate recomputed by two readers or shared as two instances over different inputs is two nodes, with an edge per input), its cost, the accepted accuracy per query and the search report | `select_plan` (`asap_plan_selection`); the facade (`run_planning`, output `PlanningRun`) runs it once and builds the selected `PhysicalWorkloadPlan` with `AssignmentRealizer::realize`, one plan node per selected node | | 4. Execution | The selected `PhysicalASAPDAG` → query results | Same: an `InstallablePlan` (`{dag, query_texts}`) → query results | The deployment runtime installs the `InstallablePlan` | @@ -611,7 +611,7 @@ What changed with the memo: jointly. - Stage 2 is no longer a pass over whole candidate DAGs. It implements every operator node of every candidate for a memo group once, enumerates each - node's timings and materializations, and prunes what cannot be built, + node's timings and lifetimes, and prunes what cannot be built, used or kept; Stage 3 selects among what remains. - The concrete summary-state groups are expanded by Stage 3's search today, through the Stage 1 functions above. A planned change moves this expansion @@ -1198,21 +1198,26 @@ the `DataWorkload`. Typical outcomes: A shared summary is materialized once for all its consumers. See Example 4. -The planner implements a subset of these options today. Stage 2 enumerates +The planner implements a subset of these options today. In code each option +is a timing and a lifetime (`PhysicalProperties`, #1200): materialized at +ingestion time is ingestion time with lifetime `AcrossEvaluations`; +materialized at query time is query time with lifetime `OneEvaluation` +(reused within one evaluation) or `AcrossEvaluations` (kept for later +evaluations); not materialized is lifetime `None`. Stage 2 enumerates materialization for summary builds (`SummaryAgg` and `SummaryTumblingWindowChain`); each -gets `NotMaterialized`, `MatAtIngestion(Memory)` when it is eligible to run -at ingestion time, and `MatAtQuery(Memory)` when two or more queries read -it. Of every other sub-DAG that two or more queries read (for example a -`Scan` that a 1 m and a 5 m window both read), only the highest node is a -materialization candidate: one that a query's output, or a node only one -query reads, consumes. It gets `NotMaterialized` and `MatAtQuery(Memory)` -only, since raw rows are not maintained at ingestion time. Below an -ingestion-time build it stays `NotMaterialized`: the ingestion side reads -its own copy. A `MatAtQuery` state is reused within one evaluation only. When the -deployment's capabilities declare `query_time_results_retained`, a -tumbling-window chain that builds exactly one new tumbling window per evaluation also gets -`MatAtQueryKeptAcrossEvaluations(Memory)`: the tumbling windows built at query time are -kept for the next evaluations. Nothing is placed on disk yet. +is offered not kept, kept at ingestion time `AcrossEvaluations(Memory)` when +it is eligible to run at ingestion time, and kept at query time +`OneEvaluation(Memory)` when two or more queries read it. Of every other +sub-DAG that two or more queries read (for example a `Scan` that a 1 m and a +5 m window both read), only the highest node is a materialization candidate: +one that a query's output, or a node only one query reads, consumes. It is +offered not kept and `OneEvaluation(Memory)` only, since raw rows are not +maintained at ingestion time. Below an ingestion-time build it stays not +kept: the ingestion side reads its own copy. When the deployment's +capabilities declare `query_time_results_retained`, a tumbling-window chain +that builds exactly one new tumbling window per evaluation is also offered +query time `AcrossEvaluations(Memory)`: the tumbling windows built at query +time are kept for the next evaluations. Nothing is placed on disk yet. A runtime builds every ingestion-time state on the grid of its width anchored at the epoch, so an ingestion-time build must end on that grid at every diff --git a/docs/develop_docs/asap-aware-mapping-architecture.md b/docs/develop_docs/asap-aware-mapping-architecture.md index d638c7a36..e48219803 100644 --- a/docs/develop_docs/asap-aware-mapping-architecture.md +++ b/docs/develop_docs/asap-aware-mapping-architecture.md @@ -17,7 +17,7 @@ in `asap-integration-tests` (`crate_graph`) checks these edges with | Crate | Role | | --- | --- | -| `asap-types` (`crates/types`) | Shared vocabulary, by IR section: `ir::operator` (`OperatorNode`, `NonASAPOp`, `ASAPOp`, operator parameters, `AggIntent`), `ir::scalar` (`ScalarExpr`, `ColumnRef`), `ir::schema` (`Schema`, `FieldDataType`, summary-state types such as `SketchAlgorithm` and `FamilyCapability`), `ir::properties` (`AccuracyTarget`, `AccuracyMetric`, `AccuracyGuarantee`, execution timing, summary coverage), plus `ir::flat` and `ir::physical_export`; the planner inputs (`workload`); Stage 2 decision data (`physical`: `Materialization`, tumbling windows) | +| `asap-types` (`crates/types`) | Shared vocabulary, by IR section: `ir::operator` (`OperatorNode`, `NonASAPOp`, `ASAPOp`, operator parameters, `AggIntent`), `ir::scalar` (`ScalarExpr`, `ColumnRef`), `ir::schema` (`Schema`, `FieldDataType`, summary-state types such as `SketchAlgorithm` and `FamilyCapability`), `ir::properties` (`AccuracyTarget`, `AccuracyMetric`, `AccuracyGuarantee`, execution timing, summary coverage), plus `ir::flat` and `ir::physical_export`; the planner inputs (`workload`); Stage 2 decision data (`physical`: `PhysicalProperties` (timing and `Lifetime`), tumbling windows) | | `asap-frontend-sql`, `asap-frontend-promql`, `asap-frontend-metricsql` (with `asap-frontend-common`) | Stage 0, the query-language frontends: lower each query into the logical DAG (`QueryRoot`s of `NonASAPOp` nodes, no summaries, no timing) | | `asap-logical-asap-optimization` (`crates/logical-asap-optimization`) | Stage 1: Pass 1 and Pass 2 (the memo rules) | | `asap-accuracy` (`crates/accuracy`) | The accuracy model the stages share: the analytical rules (per-family estimators, composition, budget split, target check) and the deployment's `AccuracyModel` and `AccuracyEvidenceProvider`; depends only on `asap-types` | @@ -71,8 +71,8 @@ same pipeline behind the `OptimizationPass` trait. | Pass 2 memo rules: shared producers (identical expressions by memo group identity, one build at different sizes), scan-label widening, window composition (tumbling windows), rollup, exact top-k reuse and finer-aggregate reuse | `asap-logical-asap-optimization`, `pass2/memo/rules/` and `pass2/memo/window_candidates.rs`, over the helpers in `pass2/asap_aware_cse.rs` | | Enumeration of the plans a memo stands for (reference pricer, DAG viewer) | `asap-logical-asap-optimization`, `pass2/memo/enumeration.rs` | | What each summary family can merge and answer (`FamilyCapability::of`: `merge_inputs`, `readouts`) | `asap-types`, `ir/schema/family_capability.rs` | -| Stage 2: materialization options per summary build (`NotMaterialized`, `MatAtIngestion`, `MatAtQuery`, `MatAtQueryKeptAcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | -| Timing and data-state edge rules applied from a `MaterializationAssignment` | `asap-types`, `ir/properties/timing.rs` and `ir/properties/execution_data_state.rs`; `Materialization` in `physical/materialization.rs` | +| Stage 2: materialization options per summary build (not kept; kept at ingestion time `AcrossEvaluations`; kept at query time `OneEvaluation` or `AcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | +| Timing and data-state edge rules applied from a `MaterializationAssignment` | `asap-types`, `ir/properties/timing.rs` and `ir/properties/execution_data_state.rs`; `PhysicalProperties` and `Lifetime` in `physical/properties.rs` | | Stage 3: accuracy check, latency check, resource usage (`ResourceUsage`), cost models 1–3 (`CostModel`), measured operation costs | `asap-plan-selection`, `lib.rs`; `asap-cost`, `lib.rs` and `measured.rs` | | The analytical per-operator resource model Stage 3 measures with | `asap-cost`, `analytical.rs` and `operator_statistics.rs` | | The accuracy algebra: per-family guarantees, composition, budget split; guarantee propagation through a DAG; sizing a summary for its target, (ε, δ) budget and default sizes | `asap-accuracy` (`AccuracyModel`, `BuiltinAccuracyModel`, `estimators/`, `composition.rs`, `budget.rs`, `propagation.rs`, `sizing.rs`) | @@ -99,7 +99,7 @@ The unwired maintained-population rule has been removed as well; no Stage 1 pass tumbling windows or reused, and each subset of their candidates becomes another Stage 1 candidate. 3. **Stage 2** gives each summary build its materialization options and emits - one physical candidate per assignment (the all-`NotMaterialized` one + one physical candidate per assignment (the all-not-kept one first), skipping assignments that put a build at ingestion time over one that is not. 4. **Stage 3** checks each physical candidate: every query's root guarantee diff --git a/docs/develop_docs/asap-aware-mapping-contracts.md b/docs/develop_docs/asap-aware-mapping-contracts.md index 6086507c2..775081130 100644 --- a/docs/develop_docs/asap-aware-mapping-contracts.md +++ b/docs/develop_docs/asap-aware-mapping-contracts.md @@ -15,7 +15,7 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types | --- | --- | --- | | Stage 0 (frontends) | `NonASAPOp` nodes only; aggregates carry `AggIntent` measures with each query's `AccuracyTarget` as written | none | | Stage 1 (`compose_logical_candidate`, Pass 2 rules) | `ASAPOp` nodes where a candidate chose an exact accumulator or a summary (`SummaryAgg`, `SummaryTumblingWindowChain`, `SummaryMerge`, `SummaryEstimate`, `FinalizeExactAccumulator`); everything else stays `NonASAPOp` | none: Stage 1 never decides when anything runs | -| Stage 2 (`generate_physical_asap_memo_candidates`; a selected plan built by `Stage2AssignmentRealizer`) | the same operators, with a `Materialization` on each summary build | every node timed from the candidate's `MaterializationAssignment` | +| Stage 2 (`generate_physical_asap_memo_candidates`; a selected plan built by `Stage2AssignmentRealizer`) | the same operators, with a timing and a `Lifetime` on each summary build | every node timed from the candidate's `MaterializationAssignment` | - Structurally equal sub-DAGs are interned before Stage 1 (`stage0/cse.rs` in `asap_logical_asap_optimization`), so Stage 1 compares nodes by structure and Pass 2 @@ -78,13 +78,14 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types ## 4. Stage 2 - Only summary builds (`SummaryAgg`, `SummaryTumblingWindowChain`) get materialization - options: `NotMaterialized` always; `MatAtIngestion(Memory)` when the build - is eligible to run as data arrives; `MatAtQuery(Memory)` when two or more - queries read it (reused within one evaluation); - `MatAtQueryKeptAcrossEvaluations(Memory)` for a tumbling-window chain that + options, each a timing and a lifetime (`PhysicalProperties`): not kept always; + kept at ingestion time, `AcrossEvaluations(Memory)`, when the build is + eligible to run as data arrives; kept at query time for `OneEvaluation(Memory)` + when two or more queries read it (reused within one evaluation); kept at + query time `AcrossEvaluations(Memory)` for a tumbling-window chain that builds one new tumbling window per evaluation, when the deployment declares `query_time_results_retained`. -- One `PhysicalCandidate` per assignment, the all-`NotMaterialized` one first +- One `PhysicalCandidate` per assignment, the all-not-kept one first (`P`, then `P-m`). An assignment that puts a build at ingestion time over one that is not is not generated. A logical candidate Stage 2 cannot implement becomes a `PrunedCandidate` with its reason. @@ -98,7 +99,7 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types candidate no buildable input, query output or reader count can use is removed (`InputHasNoBuildableProducer`, `ReachesNoQueryOutput`, `TooFewQueryReaders`). Stage 2 emits one candidate per operator node, - timing and materialization; it makes no execution-scope copies. + timing and lifetime; it makes no execution-scope copies. ## 5. Stage 3 diff --git a/docs/develop_docs/extend-asap-aware-mapping.md b/docs/develop_docs/extend-asap-aware-mapping.md index 9c03a415e..0eff8855e 100644 --- a/docs/develop_docs/extend-asap-aware-mapping.md +++ b/docs/develop_docs/extend-asap-aware-mapping.md @@ -76,8 +76,9 @@ contains the candidate and that Stage 3 prices it. ## 3. Add a Stage 2 materialization option -1. Add the `Materialization` variant - (`crates/types/src/physical/materialization.rs`) and its timing in +1. Add the `Lifetime` variant or the valid (timing, lifetime) pair + (`crates/types/src/physical/properties.rs`, `PhysicalProperties::new` and + `readable_at`) and its placement in `crates/types/src/ir/properties/timing.rs`, with its data-state edge rules. 2. Offer it in `crates/physical-asap-optimization/src/lib.rs` (the `MaterializationCandidate` options), after the existing options so default diff --git a/docs/develop_docs/library-api.md b/docs/develop_docs/library-api.md index 03f3a695c..b70866ccb 100644 --- a/docs/develop_docs/library-api.md +++ b/docs/develop_docs/library-api.md @@ -197,7 +197,7 @@ asap_plan_selection::select_plan( | --- | --- | | `PlanningModels::new(accuracy, evidence)` | Your `&dyn AccuracyModel` and `&dyn AccuracyEvidenceProvider`, with default cost inputs and deployment capabilities; `with_accuracy` and `with_evidence` replace one of them | | `PlanningModels::builtin()` | Built-in accuracy model (`BuiltinAccuracyModel`) and no extra evidence (`NoAccuracyEvidence`). `with_cost_inputs(&settings)` sets the deployment's `CostInputs`; `with_deployment_capabilities(&capabilities)` sets its `DeploymentCapabilities` (field `deployment_capabilities`) | -| `DeploymentCapabilities` (`asap_logical_asap_optimization`, re-exported as `asap_planner::DeploymentCapabilities`) | What the executor supports: `supported_summaries` (`None`, the default, supports every summary the planner builds; otherwise `SupportedSummary { family: SketchAlgorithm, readouts: Vec }` entries; Pass 1 prunes others with `PruneReason::UnsupportedByDeployment`), `raw_data_retained` (default `true`; when `false`, a candidate that scans raw data at query time is pruned by Stage 2, and stored data is refused with `asap_planner::SelectionError::InvalidDeploymentCapabilities`) and `query_time_results_retained` (default `false`; when `true`, Stage 2 offers `MatAtQueryKeptAcrossEvaluations` for tumbling windows) | +| `DeploymentCapabilities` (`asap_logical_asap_optimization`, re-exported as `asap_planner::DeploymentCapabilities`) | What the executor supports: `supported_summaries` (`None`, the default, supports every summary the planner builds; otherwise `SupportedSummary { family: SketchAlgorithm, readouts: Vec }` entries; Pass 1 prunes others with `PruneReason::UnsupportedByDeployment`), `raw_data_retained` (default `true`; when `false`, a candidate that scans raw data at query time is pruned by Stage 2, and stored data is refused with `asap_planner::SelectionError::InvalidDeploymentCapabilities`) and `query_time_results_retained` (default `false`; when `true`, Stage 2 offers query-time `AcrossEvaluations` for tumbling-window chains) | | `CostInputs` (`asap_cost`) | `cost_model`, `resource_speed` (`ms_per_cpu_op`, `ms_per_scanned_byte`), `non_repeating_query_horizon_seconds` (default 3,600) and `measured_operation_costs` (`MeasuredOperationCosts`, default empty: `operators`, one `OperatorCost { operator, phase, sketch / exact / measure, ns_per_unit, ns_per_invocation, memory_bytes_per_state }` per measured operator kind, phase and family; `ns_per_evaluation` per query request; `provenance` (executor version, machine). A node with an entry is priced from it, a sketch between the two nearest measured sizes; every other node from the formulas times one calibration factor fitted from the measured nodes; each node's `NodeCost::price_source` says which. The earlier JSON array of `MeasuredOperationCost { sketch, operation, cpu_ns_per_operation }` still loads) | | `CostModel::UsageOverTime(ResourceUnitCost)` | Cost model 1 (default, `ResourceUnitCost::illustrative()`): unit cost × usage per second; the cheapest valid candidate wins | | `CostModel::ProvisionedCapacity(ResourceUnitCost)` | Cost model 2: unit cost × peak memory, peak CPU cores and disk; the cheapest valid candidate wins | diff --git a/docs/develop_docs/pre-asap-ir.md b/docs/develop_docs/pre-asap-ir.md index 5fcd74c4c..fb93b8ae9 100644 --- a/docs/develop_docs/pre-asap-ir.md +++ b/docs/develop_docs/pre-asap-ir.md @@ -34,7 +34,7 @@ pub struct OperatorNode { pub schema: Schema, // output schema, derived at construction pub guarantee: Option, // None until accuracy assessment establishes one pub timing: Option, // None until a materialization assignment is applied - pub materialization: Materialization, // NotMaterialized until Stage 2 assigns one + pub lifetime: Lifetime, // None until Stage 2 keeps the node's output } ``` @@ -50,9 +50,9 @@ pub struct OperatorNode { - `timing` is `None` in every front-end DAG and every candidate. It is written by `ir::timing::apply_materialization_timings` (see the Post-ASAP IR document); export rejects an untimed node. -- `materialization` is `NotMaterialized` in every front-end DAG. Stage 2 writes it, with +- `lifetime` is `Lifetime::None` in every front-end DAG. Stage 2 writes it, with `timing`, through `ir::timing::apply_materialization_timings` from its materialization - assignment. + assignment; together they are the node's `PhysicalProperties`. `OperatorNode::children()` returns the operator's inputs in field order followed by the operator nodes its scalar expressions read (see "Scalar expressions"). Every DAG traversal — diff --git a/tools/dag-viewer/README.md b/tools/dag-viewer/README.md index c6800ee1c..f713f4a0f 100644 --- a/tools/dag-viewer/README.md +++ b/tools/dag-viewer/README.md @@ -9,7 +9,7 @@ document shows: - **Stage 1**, the logical candidates of the memo and the selected plan's logical DAG (`L1`); - **Stage 2**, the selected plan as an executable physical DAG (`P1`), with - each node's timing and materialization, and the physical candidates Stage 2 + each node's timing and lifetime, and the physical candidates Stage 2 pruned; - **Stage 3**, the selected plan's cost, the accuracy it accepted per query, its materialized views and the search report. @@ -78,7 +78,7 @@ To run it, see [RUNNING.md](RUNNING.md). candidates are filled green with `✓ selected`. Clicking a candidate or a group shows its nodes, children, parents and queries in the details. - **Details**: click a node for its operator, the queries reaching it, - timing, materialization, output schema, guarantee and Stage 3 cost; click + timing, lifetime, output schema, guarantee and Stage 3 cost; click an edge for its schema and data state. Other documents open with **Open stage document or workload…**, by dropping diff --git a/tools/dag-viewer/app.js b/tools/dag-viewer/app.js index 3c1b4e877..fa17338d6 100644 --- a/tools/dag-viewer/app.js +++ b/tools/dag-viewer/app.js @@ -124,7 +124,7 @@ if (d.tumblingWindowOf !== undefined) items.push(['tumbling window', `${d.tumblingWindowIndex + 1} of ${body.tumbling_window_count} of SummaryTumblingWindowChain ${d.tumblingWindowOf}, window ${tumblingWindowTimeText(d.tumbling_window, body.tumbling_window_width_ms)}`]); if (d.expandable) items.push(['tumbling windows', `${body.tumbling_window_count} × ${durationText(body.tumbling_window_width_ms)} (click the chain to show them, a tumbling window to hide them)`]); if (d.timing !== undefined) items.push(['runs at', formatTiming(d.timing)]); - if (n.materialization) items.push(['materialization', compactWire(n.materialization)]); + if (n.lifetime) items.push(['lifetime', compactWire(n.lifetime)]); if (n.output_state && n.output_state.primitive) items.push(['output primitive', compactWire(n.output_state.primitive)]); if (d.cost) { const value = typeof d.cost.cost_per_second === 'number' diff --git a/tools/dag-viewer/memo.js b/tools/dag-viewer/memo.js index 5216dbab3..d13aa801b 100644 --- a/tools/dag-viewer/memo.js +++ b/tools/dag-viewer/memo.js @@ -50,11 +50,11 @@ const memoIsNode = (nodes, id) => Number.isInteger(id) && id >= 0 && id < nodes. // One line per entry of a stage's `pruned_candidates` on group `group`: // Pass 1's `candidate`, or Stage 2's operator with its timing, -// materialization and scope copy; then the reason. 'none' without any. +// lifetime and scope copy; then the reason. 'none' without any. function memoPrunedText(entries, group) { const lines = (Array.isArray(entries) ? entries : []).filter((p) => p && p.group === group).map((p) => { const what = 'candidate' in p ? p.candidate - : `node ${p.operator_node} ${p.operator} ${p.timing} ${JSON.stringify(p.materialization)}`; + : `node ${p.operator_node} ${p.operator} ${p.timing} ${JSON.stringify(p.lifetime)}`; return `${what}: ${p.reason}`; }); return lines.length ? lines.join('; ') : 'none'; diff --git a/tools/dag-viewer/stages.js b/tools/dag-viewer/stages.js index aff3da8fa..ebe62b60c 100644 --- a/tools/dag-viewer/stages.js +++ b/tools/dag-viewer/stages.js @@ -224,7 +224,7 @@ function stageDag(dag, physical) { const [kind, body] = stageOperatorParts(node.payload); return { id: node.id, kind, body, schema: node.output_schema, guarantee: node.guarantee, - materialization: node.materialization, timing: node.output_state ? node.output_state.timing : undefined, raw: node, + lifetime: node.lifetime, timing: node.output_state ? node.output_state.timing : undefined, raw: node, }; }); const edges = dag.edges.map((edge) => ({ producer: edge.producer, consumer: edge.consumer, raw: edge })); @@ -242,7 +242,7 @@ function stageDag(dag, physical) { stageLogicalChildren(body).forEach((producer) => edges.push({ producer, consumer: id, raw: null })); return { id, kind, body, schema: node.schema, guarantee: node.guarantee, - materialization: node.materialization, timing: node.timing === null ? undefined : node.timing, raw: node, + lifetime: node.lifetime, timing: node.timing === null ? undefined : node.timing, raw: node, }; }); const queries = dag.roots.map((root) => ('Scalar' in root ? { scalar: root.Scalar } : { node: root.Operator })); From 619bd36eac5ff8cc4a300160ca3755a87c156a15 Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Wed, 4 Nov 2026 23:19:13 +0000 Subject: [PATCH 2/9] test: regenerate snapshots and fixtures for the lifetime field (rename only) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- .../corpus_snapshots/o11y_bench/q02.json | 16 +++---- .../corpus_snapshots/o11y_bench/q05.json | 36 ++++++++-------- .../corpus_snapshots/o11y_bench/q06.json | 22 +++++----- .../corpus_snapshots/o11y_bench/q11.json | 14 +++---- .../corpus_snapshots/o11y_bench/q12.json | 4 +- .../corpus_snapshots/o11y_bench/q18.json | 34 +++++++-------- .../corpus_snapshots/o11y_bench/q19.json | 30 ++++++------- .../corpus_snapshots/o11y_bench/q20.json | 8 ++-- .../corpus_snapshots/o11y_bench/q21.json | 16 +++---- .../corpus_snapshots/o11y_bench/q22.json | 14 +++---- .../corpus_snapshots/o11y_bench/q23.json | 14 +++---- .../corpus_snapshots/o11y_bench/q25.json | 30 ++++++------- .../corpus_snapshots/o11y_bench/q26.json | 14 +++---- .../corpus_snapshots/o11y_bench/q27.json | 8 ++-- .../fuzz-issue903-raw-retained.json | 14 +++---- .../nested-windows-15m-1h-mvp.json | 18 ++++---- .../quantile-grouped-mvp.json | 26 ++++++------ .../quantile-single-mvp.json | 12 +++--- ...random-mixed-seed-862-long-w01-q3-mvp.json | 26 ++++++------ .../random-mixed-seed-862-w01-q3-q8-mvp.json | 42 +++++++++---------- .../random-mixed-seed-862-w02-q2-q7-mvp.json | 42 +++++++++---------- .../ratio-of-quantiles-1h-mvp.json | 20 ++++----- .../shared-quantiles-1h-mvp.json | 18 ++++---- .../topk-rate-guarantees-ignored-mvp.json | 16 +++---- .../plan_wire_version_10.json | 2 +- .../stored_outputs_on_main.json | 16 +++---- .../test-fixtures/memo-enumeration-small.json | 2 +- .../dag-viewer/test-fixtures/memo-small.json | 2 +- 28 files changed, 258 insertions(+), 258 deletions(-) diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q02.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q02.json index d803d90f7..5cb411f72 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q02.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q02.json @@ -721,7 +721,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -861,8 +861,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -954,7 +954,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1044,7 +1044,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1112,7 +1112,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1197,7 +1197,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1257,7 +1257,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": false, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q05.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q05.json index b986b993f..4d42935a1 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q05.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q05.json @@ -880,7 +880,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1034,8 +1034,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -1127,7 +1127,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1217,7 +1217,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1285,7 +1285,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1356,7 +1356,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1404,7 +1404,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1528,8 +1528,8 @@ { "guarantee": null, "id": 7, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -1613,7 +1613,7 @@ { "guarantee": null, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1695,7 +1695,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1755,7 +1755,7 @@ { "guarantee": null, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1826,7 +1826,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1874,7 +1874,7 @@ } }, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1932,7 +1932,7 @@ } }, "id": 13, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1971,7 +1971,7 @@ { "guarantee": null, "id": 14, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2040,7 +2040,7 @@ } }, "id": 15, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q06.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q06.json index 99affb00a..8cca94ae9 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q06.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q06.json @@ -569,7 +569,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -709,8 +709,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -802,7 +802,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -892,7 +892,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -960,7 +960,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1045,7 +1045,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1105,7 +1105,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": false, "fields": [ @@ -1172,7 +1172,7 @@ } }, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": false, "fields": [ @@ -1211,7 +1211,7 @@ { "guarantee": null, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": false, "fields": [ @@ -1280,7 +1280,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": false, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q11.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q11.json index 16f3c5c73..33b444675 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q11.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q11.json @@ -328,7 +328,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -438,7 +438,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -495,7 +495,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -566,7 +566,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -614,7 +614,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -653,7 +653,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -722,7 +722,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q12.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q12.json index 2a4d99a83..8f1b22d92 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q12.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q12.json @@ -133,7 +133,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -274,7 +274,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q18.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q18.json index cc49899a7..a491b2f63 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q18.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q18.json @@ -7148,7 +7148,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7319,7 +7319,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7391,8 +7391,8 @@ { "guarantee": null, "id": 2, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -7484,7 +7484,7 @@ { "guarantee": null, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7574,7 +7574,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7642,7 +7642,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7713,7 +7713,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7761,7 +7761,7 @@ } }, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7902,7 +7902,7 @@ } }, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7966,8 +7966,8 @@ { "guarantee": null, "id": 9, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -8051,7 +8051,7 @@ { "guarantee": null, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8133,7 +8133,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8193,7 +8193,7 @@ { "guarantee": null, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8264,7 +8264,7 @@ } }, "id": 13, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8312,7 +8312,7 @@ } }, "id": 14, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q19.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q19.json index 2d5150c66..2e30b8d58 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q19.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q19.json @@ -7012,7 +7012,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7166,8 +7166,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -7259,7 +7259,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7349,7 +7349,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7417,7 +7417,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7488,7 +7488,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7536,7 +7536,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7660,8 +7660,8 @@ { "guarantee": null, "id": 7, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -7745,7 +7745,7 @@ { "guarantee": null, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7827,7 +7827,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7887,7 +7887,7 @@ { "guarantee": null, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7958,7 +7958,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8006,7 +8006,7 @@ } }, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q20.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q20.json index 6b44c713b..3adc6ca62 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q20.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q20.json @@ -219,7 +219,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -329,7 +329,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -386,7 +386,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -457,7 +457,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q21.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q21.json index 8546dd2b2..3ffc88b31 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q21.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q21.json @@ -694,7 +694,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -835,7 +835,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -899,8 +899,8 @@ { "guarantee": null, "id": 2, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -984,7 +984,7 @@ { "guarantee": null, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1066,7 +1066,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1126,7 +1126,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1197,7 +1197,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q22.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q22.json index b7c91f320..e0a83a8d0 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q22.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q22.json @@ -630,7 +630,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -754,8 +754,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -839,7 +839,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -921,7 +921,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -981,7 +981,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1052,7 +1052,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q23.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q23.json index 2ad030eed..5156b5315 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q23.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q23.json @@ -560,7 +560,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -684,8 +684,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -769,7 +769,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -851,7 +851,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -911,7 +911,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -982,7 +982,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q25.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q25.json index 9f4988b12..c69ea0939 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q25.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q25.json @@ -5332,7 +5332,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5486,8 +5486,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -5579,7 +5579,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5669,7 +5669,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5737,7 +5737,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5808,7 +5808,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5856,7 +5856,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -5980,8 +5980,8 @@ { "guarantee": null, "id": 7, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -6065,7 +6065,7 @@ { "guarantee": null, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6147,7 +6147,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6207,7 +6207,7 @@ { "guarantee": null, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6278,7 +6278,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6326,7 +6326,7 @@ } }, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q26.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q26.json index e33bf4553..fbdeba67f 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q26.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q26.json @@ -2618,7 +2618,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2711,8 +2711,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -2788,7 +2788,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2862,7 +2862,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2914,7 +2914,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2985,7 +2985,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/corpus_snapshots/o11y_bench/q27.json b/crates/devtools/tests/corpus_snapshots/o11y_bench/q27.json index e119b2b13..e87f425a7 100644 --- a/crates/devtools/tests/corpus_snapshots/o11y_bench/q27.json +++ b/crates/devtools/tests/corpus_snapshots/o11y_bench/q27.json @@ -219,7 +219,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -329,7 +329,7 @@ } }, "id": 1, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -386,7 +386,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -457,7 +457,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/fuzz-issue903-raw-retained.json b/crates/devtools/tests/sketch_plan_snapshots/fuzz-issue903-raw-retained.json index 225a81a8a..f27b75631 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/fuzz-issue903-raw-retained.json +++ b/crates/devtools/tests/sketch_plan_snapshots/fuzz-issue903-raw-retained.json @@ -378,7 +378,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -488,8 +488,8 @@ } }, "id": 1, - "materialization": { - "MatAtQuery": "Memory" + "lifetime": { + "OneEvaluation": "Memory" }, "output_schema": { "closed": true, @@ -564,7 +564,7 @@ } }, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -634,7 +634,7 @@ { "guarantee": null, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -750,7 +750,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -834,7 +834,7 @@ } }, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/nested-windows-15m-1h-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/nested-windows-15m-1h-mvp.json index 9b4fb2c61..54a2d6f95 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/nested-windows-15m-1h-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/nested-windows-15m-1h-mvp.json @@ -2802,7 +2802,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2895,8 +2895,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -2986,7 +2986,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3085,7 +3085,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3176,7 +3176,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3249,7 +3249,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3347,7 +3347,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3438,7 +3438,7 @@ } }, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/quantile-grouped-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/quantile-grouped-mvp.json index 3baaa111e..37361b98d 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/quantile-grouped-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/quantile-grouped-mvp.json @@ -1898,7 +1898,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2007,8 +2007,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -2106,7 +2106,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2212,7 +2212,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2311,7 +2311,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2398,7 +2398,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2573,7 +2573,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2616,7 +2616,7 @@ { "guarantee": null, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2701,7 +2701,7 @@ } }, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2761,7 +2761,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2932,7 +2932,7 @@ } }, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3092,7 +3092,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/quantile-single-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/quantile-single-mvp.json index 4f357790a..6583082f6 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/quantile-single-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/quantile-single-mvp.json @@ -1461,7 +1461,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1554,8 +1554,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -1647,7 +1647,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1739,7 +1739,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1823,7 +1823,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-long-w01-q3-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-long-w01-q3-mvp.json index 04ea77719..d569fff3a 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-long-w01-q3-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-long-w01-q3-mvp.json @@ -12158,7 +12158,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12267,8 +12267,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -12366,7 +12366,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12472,7 +12472,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12571,7 +12571,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12658,7 +12658,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12833,7 +12833,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12876,7 +12876,7 @@ { "guarantee": null, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -12961,7 +12961,7 @@ } }, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -13021,7 +13021,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -13192,7 +13192,7 @@ } }, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -13352,7 +13352,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w01-q3-q8-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w01-q3-q8-mvp.json index f9db2cbc5..95d124a1c 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w01-q3-q8-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w01-q3-q8-mvp.json @@ -6490,7 +6490,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6599,8 +6599,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -6698,7 +6698,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6804,7 +6804,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6903,7 +6903,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -6990,7 +6990,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7165,7 +7165,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7208,7 +7208,7 @@ { "guarantee": null, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7293,7 +7293,7 @@ } }, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7353,7 +7353,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7524,7 +7524,7 @@ } }, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7684,7 +7684,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7759,7 +7759,7 @@ } }, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7868,8 +7868,8 @@ { "guarantee": null, "id": 13, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -7953,7 +7953,7 @@ { "guarantee": null, "id": 14, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8035,7 +8035,7 @@ } }, "id": 15, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8112,7 +8112,7 @@ } }, "id": 16, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8201,7 +8201,7 @@ } }, "id": 17, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8283,7 +8283,7 @@ } }, "id": 18, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w02-q2-q7-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w02-q2-q7-mvp.json index 6de034914..94d046d27 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w02-q2-q7-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/random-mixed-seed-862-w02-q2-q7-mvp.json @@ -7250,7 +7250,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7359,8 +7359,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -7458,7 +7458,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7564,7 +7564,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7663,7 +7663,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7750,7 +7750,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7925,7 +7925,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -7968,7 +7968,7 @@ { "guarantee": null, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8053,7 +8053,7 @@ } }, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8113,7 +8113,7 @@ } }, "id": 9, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8284,7 +8284,7 @@ } }, "id": 10, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8444,7 +8444,7 @@ } }, "id": 11, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8519,7 +8519,7 @@ } }, "id": 12, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8628,8 +8628,8 @@ { "guarantee": null, "id": 13, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -8713,7 +8713,7 @@ { "guarantee": null, "id": 14, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8795,7 +8795,7 @@ } }, "id": 15, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8872,7 +8872,7 @@ } }, "id": 16, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -8961,7 +8961,7 @@ } }, "id": 17, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -9043,7 +9043,7 @@ } }, "id": 18, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/ratio-of-quantiles-1h-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/ratio-of-quantiles-1h-mvp.json index 0d170be65..266118af6 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/ratio-of-quantiles-1h-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/ratio-of-quantiles-1h-mvp.json @@ -2890,7 +2890,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2983,8 +2983,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -3074,7 +3074,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3172,7 +3172,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3263,7 +3263,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3336,7 +3336,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3434,7 +3434,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3525,7 +3525,7 @@ } }, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3598,7 +3598,7 @@ { "guarantee": null, "id": 8, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/shared-quantiles-1h-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/shared-quantiles-1h-mvp.json index 227c9d39c..fa094b72a 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/shared-quantiles-1h-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/shared-quantiles-1h-mvp.json @@ -2802,7 +2802,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2895,8 +2895,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -2986,7 +2986,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3084,7 +3084,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3175,7 +3175,7 @@ } }, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3248,7 +3248,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3346,7 +3346,7 @@ } }, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -3437,7 +3437,7 @@ } }, "id": 7, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/devtools/tests/sketch_plan_snapshots/topk-rate-guarantees-ignored-mvp.json b/crates/devtools/tests/sketch_plan_snapshots/topk-rate-guarantees-ignored-mvp.json index b49a890c2..3d269fb2c 100644 --- a/crates/devtools/tests/sketch_plan_snapshots/topk-rate-guarantees-ignored-mvp.json +++ b/crates/devtools/tests/sketch_plan_snapshots/topk-rate-guarantees-ignored-mvp.json @@ -1571,7 +1571,7 @@ } }, "id": 0, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1680,8 +1680,8 @@ { "guarantee": null, "id": 1, - "materialization": { - "MatAtIngestion": "Memory" + "lifetime": { + "AcrossEvaluations": "Memory" }, "output_schema": { "closed": true, @@ -1765,7 +1765,7 @@ { "guarantee": null, "id": 2, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1847,7 +1847,7 @@ } }, "id": 3, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1907,7 +1907,7 @@ { "guarantee": null, "id": 4, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -1984,7 +1984,7 @@ { "guarantee": null, "id": 5, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ @@ -2032,7 +2032,7 @@ { "guarantee": null, "id": 6, - "materialization": "NotMaterialized", + "lifetime": "None", "output_schema": { "closed": true, "fields": [ diff --git a/crates/integration-tests/tests/materialized_view_fixtures/plan_wire_version_10.json b/crates/integration-tests/tests/materialized_view_fixtures/plan_wire_version_10.json index 515db4302..d2e26ea78 100644 --- a/crates/integration-tests/tests/materialized_view_fixtures/plan_wire_version_10.json +++ b/crates/integration-tests/tests/materialized_view_fixtures/plan_wire_version_10.json @@ -1 +1 @@ -{"dag":{"schema_version":10,"dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[1]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}}],"roots":[5,6],"scalar_roots":[]}},"queries":[{"query":"sum by (job) (sum_over_time(m[1m]))","root_node_id":5},{"query":"sum by (job, instance) (sum_over_time(m[1m]))","root_node_id":6}],"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"db0c9241a79202b6925e84aef010e89a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"3c90a6b5ff3ecaa445ea9bf285e1dc0b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}],"query_time_raw_windows":[],"selection":null} +{"dag": {"schema_version": 10, "dag": {"edges": [{"consumer": 1, "data_state": {"primitive": "Raw", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "timestamp"}, "name": "ts", "nullable": false, "table": null}, {"dtype": {"Plain": "float64"}, "name": "value", "nullable": false, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "$promql_series_identity", "nullable": false, "table": null}], "time_index": 0, "unique_keys": [[4, 0]]}, "producer": 0, "role": "Input", "window": "RequiresAlignedPanePhaseOrExactBoundaryResidual"}, {"consumer": 2, "data_state": {"primitive": "Raw", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "timestamp"}, "name": "ts", "nullable": false, "table": null}, {"dtype": {"Plain": "float64"}, "name": "value", "nullable": false, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "$promql_series_identity", "nullable": false, "table": null}], "time_index": 0, "unique_keys": [[4, 0]]}, "producer": 1, "role": "Input", "window": "RequiresAlignedPanePhaseOrExactBoundaryResidual"}, {"consumer": 3, "data_state": {"primitive": "SummaryState", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"ExactAggregate": ["Sum", "Sum"]}, "name": "state", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "producer": 2, "role": "Input", "window": "RequiresAlignedPanePhaseOrExactBoundaryResidual"}, {"consumer": 4, "data_state": {"primitive": "Raw", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "float64"}, "name": "sum", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "producer": 3, "role": "Input", "window": "RequiresAlignedPanePhaseOrExactBoundaryResidual"}, {"consumer": 5, "data_state": {"primitive": "SummaryState", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"ExactAggregate": ["Sum", "Sum"]}, "name": "state", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0]]}, "producer": 4, "role": "Input", "window": "NotApplicable"}, {"consumer": 6, "data_state": {"primitive": "SummaryState", "timing": "ingestion_time"}, "grouping": "NotApplicable", "intermediate_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"ExactAggregate": ["Sum", "Sum"]}, "name": "state", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "producer": 2, "role": "Input", "window": "NotApplicable"}], "nodes": [{"guarantee": {"provenance": [{"kind": "exact", "reason": "exact over exact inputs"}], "spec": {"accuracy_metric": "absolute", "accuracy_scope": "per_value", "error": {"op": "zero"}, "failure_probability": {"op": "zero"}}}, "id": 0, "lifetime": "None", "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "timestamp"}, "name": "ts", "nullable": false, "table": null}, {"dtype": {"Plain": "float64"}, "name": "value", "nullable": false, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "$promql_series_identity", "nullable": false, "table": null}], "time_index": 0, "unique_keys": [[4, 0]]}, "output_state": {"primitive": "Raw", "timing": "ingestion_time"}, "payload": {"NonASAP": {"Scan": {"predicates": [], "schema": {"closed": true, "fields": [{"dtype": {"Plain": "timestamp"}, "name": "ts", "nullable": false, "table": null}, {"dtype": {"Plain": "float64"}, "name": "value", "nullable": false, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "$promql_series_identity", "nullable": false, "table": null}], "time_index": 0, "unique_keys": [[4, 0]]}, "source": {"TimeSeries": {"metric": "m"}}}}}}, {"guarantee": {"provenance": [{"kind": "exact", "reason": "exact over exact inputs"}], "spec": {"accuracy_metric": "absolute", "accuracy_scope": "per_value", "error": {"op": "zero"}, "failure_probability": {"op": "zero"}}}, "id": 1, "lifetime": "None", "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "timestamp"}, "name": "ts", "nullable": false, "table": null}, {"dtype": {"Plain": "float64"}, "name": "value", "nullable": false, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "$promql_series_identity", "nullable": false, "table": null}], "time_index": 0, "unique_keys": [[4, 0]]}, "output_state": {"primitive": "Raw", "timing": "ingestion_time"}, "payload": {"NonASAP": {"TimeRange": {"child": 0, "kind": "range", "range": {"nanos": 0, "secs": 60}}}}}, {"guarantee": null, "id": 2, "lifetime": {"AcrossEvaluations": "Memory"}, "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"ExactAggregate": ["Sum", "Sum"]}, "name": "state", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "output_state": {"primitive": "SummaryState", "timing": "ingestion_time"}, "payload": {"ASAP": {"SummaryAgg": {"child": 1, "family": {"ExactAggregate": ["Sum", "Sum"]}, "filter": null, "grouping": "PerSubpopulationInstance", "input": {"item": null, "weight": {"Column": "SampleValue"}, "weight_domain": {"kind": "unknown_or_signed"}}, "reduction": {"Reduce": [2, 3]}}}}}, {"guarantee": {"provenance": [{"kind": "exact", "reason": "exact accumulator over exact input"}], "spec": {"accuracy_metric": "absolute", "accuracy_scope": "per_value", "error": {"op": "zero"}, "failure_probability": {"op": "zero"}}}, "id": 3, "lifetime": "None", "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "float64"}, "name": "sum", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "output_state": {"primitive": "Raw", "timing": "ingestion_time"}, "payload": {"ASAP": {"FinalizeExactAccumulator": {"child": 2}}}}, {"guarantee": null, "id": 4, "lifetime": {"AcrossEvaluations": "Memory"}, "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"ExactAggregate": ["Sum", "Sum"]}, "name": "state", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0]]}, "output_state": {"primitive": "SummaryState", "timing": "ingestion_time"}, "payload": {"ASAP": {"SummaryAgg": {"child": 3, "family": {"ExactAggregate": ["Sum", "Sum"]}, "filter": null, "grouping": "PerSubpopulationInstance", "input": {"item": null, "weight": {"Column": {"Named": "sum"}}, "weight_domain": {"kind": "unknown_or_signed"}}, "reduction": {"Reduce": [1]}}}}}, {"guarantee": {"provenance": [{"kind": "exact", "reason": "exact accumulator over exact input"}], "spec": {"accuracy_metric": "absolute", "accuracy_scope": "per_value", "error": {"op": "zero"}, "failure_probability": {"op": "zero"}}}, "id": 5, "lifetime": "None", "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "float64"}, "name": "sum", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0]]}, "output_state": {"primitive": "Raw", "timing": "query_time"}, "payload": {"ASAP": {"FinalizeExactAccumulator": {"child": 4}}}}, {"guarantee": {"provenance": [{"kind": "exact", "reason": "exact accumulator over exact input"}], "spec": {"accuracy_metric": "absolute", "accuracy_scope": "per_value", "error": {"op": "zero"}, "failure_probability": {"op": "zero"}}}, "id": 6, "lifetime": "None", "output_schema": {"closed": true, "fields": [{"dtype": {"Plain": "utf8"}, "name": "instance", "nullable": true, "table": null}, {"dtype": {"Plain": "utf8"}, "name": "job", "nullable": true, "table": null}, {"dtype": {"Plain": "float64"}, "name": "sum", "nullable": false, "table": null}], "time_index": null, "unique_keys": [[0, 1]]}, "output_state": {"primitive": "Raw", "timing": "query_time"}, "payload": {"ASAP": {"FinalizeExactAccumulator": {"child": 2}}}}], "roots": [5, 6], "scalar_roots": []}}, "queries": [{"query": "sum by (job) (sum_over_time(m[1m]))", "root_node_id": 5}, {"query": "sum by (job, instance) (sum_over_time(m[1m]))", "root_node_id": 6}], "stored_outputs": [{"built_at": "ingestion_run", "coverage": {"definition_id": "db0c9241a79202b6925e84aef010e89a", "selection": [{"columns": [], "relative_time": [{"excluded": -60000}, {"included": 0}]}]}, "inputs": {"raw_sample_windows": [{"end_offset_ms": 0, "scan_node_id": 0, "time_range_node_id": 1, "width_ms": 60000}], "stored_outputs": []}, "node_id": 2, "retention_ms": 60000}, {"built_at": "ingestion_run", "coverage": {"definition_id": "3c90a6b5ff3ecaa445ea9bf285e1dc0b", "selection": [{"columns": [], "relative_time": [{"excluded": -60000}, {"included": 0}]}]}, "inputs": {"raw_sample_windows": [], "stored_outputs": [2]}, "node_id": 4, "retention_ms": 60000}], "query_time_raw_windows": [], "selection": null} diff --git a/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json b/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json index 3a73c4fcf..ef0e50645 100644 --- a/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json +++ b/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json @@ -1,10 +1,10 @@ [ -{"name":"repeating p99-60m/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":18,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":34,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":33,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":35,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":34,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":36,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":37,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":36,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":38,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":37,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":39,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":40,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":39,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":41,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":40,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":42,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":43,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":42,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":44,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":43,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":45,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":46,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":45,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":47,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":46,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":48,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":49,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":48,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":50,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":49,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":51,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":52,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":51,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":53,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":52,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":35,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":38,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":41,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":44,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":47,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":50,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":53,"role":"Input","window":"NotApplicable"},{"consumer":55,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":54,"role":"Input","window":"NotApplicable"},{"consumer":56,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":55,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":200000}}}}},{"guarantee":null,"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":5,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":400000}}}}},{"guarantee":null,"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":8,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":600000}}}}},{"guarantee":null,"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":11,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":800000}}}}},{"guarantee":null,"id":13,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":14,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1000000}}}}},{"guarantee":null,"id":16,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":15,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":17,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":18,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1200000}}}}},{"guarantee":null,"id":19,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":18,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":20,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":19,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":21,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1400000}}}}},{"guarantee":null,"id":22,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":21,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":23,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":22,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":24,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1600000}}}}},{"guarantee":null,"id":25,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":24,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":26,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":25,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":27,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1800000}}}}},{"guarantee":null,"id":28,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":27,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":29,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":28,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":30,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2000000}}}}},{"guarantee":null,"id":31,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":30,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":32,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":31,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":33,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2200000}}}}},{"guarantee":null,"id":34,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":33,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":35,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":34,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":36,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2400000}}}}},{"guarantee":null,"id":37,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":36,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":38,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":37,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":39,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2600000}}}}},{"guarantee":null,"id":40,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":39,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":41,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":40,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":42,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2800000}}}}},{"guarantee":null,"id":43,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":42,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":44,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":43,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":45,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3000000}}}}},{"guarantee":null,"id":46,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":45,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":47,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":46,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":48,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3200000}}}}},{"guarantee":null,"id":49,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":48,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":50,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":49,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":51,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3400000}}}}},{"guarantee":null,"id":52,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":51,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":53,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":52,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":54,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53]}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":55,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"SummaryEstimate":{"query":{"Quantile":{"q":0.99}},"summary_input":54}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":56,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":55,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":2}}],"qualifier":null}}}}],"roots":[56],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-200000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":200000}],"stored_outputs":[]},"node_id":2,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-400000},{"included":-200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":200000,"scan_node_id":0,"time_range_node_id":4,"width_ms":200000}],"stored_outputs":[]},"node_id":5,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":400000,"scan_node_id":0,"time_range_node_id":7,"width_ms":200000}],"stored_outputs":[]},"node_id":8,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-800000},{"included":-600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":600000,"scan_node_id":0,"time_range_node_id":10,"width_ms":200000}],"stored_outputs":[]},"node_id":11,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1000000},{"included":-800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":800000,"scan_node_id":0,"time_range_node_id":13,"width_ms":200000}],"stored_outputs":[]},"node_id":14,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1200000},{"included":-1000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1000000,"scan_node_id":0,"time_range_node_id":16,"width_ms":200000}],"stored_outputs":[]},"node_id":17,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1400000},{"included":-1200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1200000,"scan_node_id":0,"time_range_node_id":19,"width_ms":200000}],"stored_outputs":[]},"node_id":20,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1600000},{"included":-1400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1400000,"scan_node_id":0,"time_range_node_id":22,"width_ms":200000}],"stored_outputs":[]},"node_id":23,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1800000},{"included":-1600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1600000,"scan_node_id":0,"time_range_node_id":25,"width_ms":200000}],"stored_outputs":[]},"node_id":26,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2000000},{"included":-1800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1800000,"scan_node_id":0,"time_range_node_id":28,"width_ms":200000}],"stored_outputs":[]},"node_id":29,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2200000},{"included":-2000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2000000,"scan_node_id":0,"time_range_node_id":31,"width_ms":200000}],"stored_outputs":[]},"node_id":32,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2400000},{"included":-2200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2200000,"scan_node_id":0,"time_range_node_id":34,"width_ms":200000}],"stored_outputs":[]},"node_id":35,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2600000},{"included":-2400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2400000,"scan_node_id":0,"time_range_node_id":37,"width_ms":200000}],"stored_outputs":[]},"node_id":38,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2800000},{"included":-2600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2600000,"scan_node_id":0,"time_range_node_id":40,"width_ms":200000}],"stored_outputs":[]},"node_id":41,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3000000},{"included":-2800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2800000,"scan_node_id":0,"time_range_node_id":43,"width_ms":200000}],"stored_outputs":[]},"node_id":44,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3200000},{"included":-3000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3000000,"scan_node_id":0,"time_range_node_id":46,"width_ms":200000}],"stored_outputs":[]},"node_id":47,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3400000},{"included":-3200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3200000,"scan_node_id":0,"time_range_node_id":49,"width_ms":200000}],"stored_outputs":[]},"node_id":50,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3600000},{"included":-3400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3400000,"scan_node_id":0,"time_range_node_id":52,"width_ms":200000}],"stored_outputs":[]},"node_id":53,"retention_ms":3600000}]}, -{"name":"repeating offset-chain/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":17,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":18,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":32,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"NotApplicable"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":300000}}}}},{"guarantee":null,"id":2,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":1,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":3,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":2,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":360000}}}}},{"guarantee":null,"id":5,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":4,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":6,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":5,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":420000}}}}},{"guarantee":null,"id":8,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":7,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":9,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":8,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":480000}}}}},{"guarantee":null,"id":11,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":10,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":12,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":11,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":13,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":540000}}}}},{"guarantee":null,"id":14,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":13,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":15,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":14,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":16,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":600000}}}}},{"guarantee":null,"id":17,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":16,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":18,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":17,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":19,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":660000}}}}},{"guarantee":null,"id":20,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":19,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":21,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":20,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":22,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":720000}}}}},{"guarantee":null,"id":23,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":22,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":24,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":23,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":25,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":780000}}}}},{"guarantee":null,"id":26,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":25,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":27,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":26,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":28,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":840000}}}}},{"guarantee":null,"id":29,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":28,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":30,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":29,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":31,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[3,6,9,12,15,18,21,24,27,30]}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":32,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"SummaryEstimate":{"query":{"Quantile":{"q":0.99}},"summary_input":31}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":33,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":32,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":2}}],"qualifier":null}}}}],"roots":[33],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-360000},{"included":-300000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":300000,"scan_node_id":0,"time_range_node_id":2,"width_ms":60000}],"stored_outputs":[]},"node_id":3,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-420000},{"included":-360000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":360000,"scan_node_id":0,"time_range_node_id":5,"width_ms":60000}],"stored_outputs":[]},"node_id":6,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-480000},{"included":-420000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":420000,"scan_node_id":0,"time_range_node_id":8,"width_ms":60000}],"stored_outputs":[]},"node_id":9,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-540000},{"included":-480000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":480000,"scan_node_id":0,"time_range_node_id":11,"width_ms":60000}],"stored_outputs":[]},"node_id":12,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-540000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":540000,"scan_node_id":0,"time_range_node_id":14,"width_ms":60000}],"stored_outputs":[]},"node_id":15,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-660000},{"included":-600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":600000,"scan_node_id":0,"time_range_node_id":17,"width_ms":60000}],"stored_outputs":[]},"node_id":18,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-720000},{"included":-660000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":660000,"scan_node_id":0,"time_range_node_id":20,"width_ms":60000}],"stored_outputs":[]},"node_id":21,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-780000},{"included":-720000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":720000,"scan_node_id":0,"time_range_node_id":23,"width_ms":60000}],"stored_outputs":[]},"node_id":24,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-840000},{"included":-780000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":780000,"scan_node_id":0,"time_range_node_id":26,"width_ms":60000}],"stored_outputs":[]},"node_id":27,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-900000},{"included":-840000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":840000,"scan_node_id":0,"time_range_node_id":29,"width_ms":60000}],"stored_outputs":[]},"node_id":30,"retention_ms":900000}]}, -{"name":"repeating rollup/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":15,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":18,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":21,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":24,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":27,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":20,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":23,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":26,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":29,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":31,"role":"Input","window":"NotApplicable"},{"consumer":33,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":32,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":34,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":300000}}}}},{"guarantee":null,"id":16,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":15,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":17,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":18,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":360000}}}}},{"guarantee":null,"id":19,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":18,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":20,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":19,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":21,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":420000}}}}},{"guarantee":null,"id":22,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":21,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":23,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":22,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":24,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":480000}}}}},{"guarantee":null,"id":25,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":24,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":26,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":25,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":27,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":540000}}}}},{"guarantee":null,"id":28,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":27,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":29,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":28,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":30,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14,17,20,23,26,29]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":31,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":30}}}},{"guarantee":null,"id":32,"materialization":{"MatAtQuery":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":31,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":33,"materialization":{"MatAtQuery":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":32}}}},{"guarantee":null,"id":34,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":33,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}}],"roots":[33,35],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-360000},{"included":-300000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":300000,"scan_node_id":0,"time_range_node_id":16,"width_ms":60000}],"stored_outputs":[]},"node_id":17,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-420000},{"included":-360000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":360000,"scan_node_id":0,"time_range_node_id":19,"width_ms":60000}],"stored_outputs":[]},"node_id":20,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-480000},{"included":-420000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":420000,"scan_node_id":0,"time_range_node_id":22,"width_ms":60000}],"stored_outputs":[]},"node_id":23,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-540000},{"included":-480000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":480000,"scan_node_id":0,"time_range_node_id":25,"width_ms":60000}],"stored_outputs":[]},"node_id":26,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-540000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":540000,"scan_node_id":0,"time_range_node_id":28,"width_ms":60000}],"stored_outputs":[]},"node_id":29,"retention_ms":600000}]}, -{"name":"repeating rate-5m/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"NotApplicable"},{"consumer":18,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":34,"role":"Input","window":"NotApplicable"},{"consumer":36,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":35,"role":"Input","window":"NotApplicable"},{"consumer":37,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":36,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}},{"guarantee":null,"id":17,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":18,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":17}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":19,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3600000}}}}},{"guarantee":null,"id":20,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":19,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":21,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":20,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":22,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3660000}}}}},{"guarantee":null,"id":23,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":22,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":24,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":23,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":25,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3720000}}}}},{"guarantee":null,"id":26,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":25,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":27,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":26,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":28,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3780000}}}}},{"guarantee":null,"id":29,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":28,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":30,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":29,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":31,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3840000}}}}},{"guarantee":null,"id":32,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":31,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":33,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":32,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":34,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[21,24,27,30,33]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}},{"guarantee":null,"id":36,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":35,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":37,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":36}}}}],"roots":[18,37],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3660000},{"included":-3600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3600000,"scan_node_id":0,"time_range_node_id":20,"width_ms":60000}],"stored_outputs":[]},"node_id":21,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3720000},{"included":-3660000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3660000,"scan_node_id":0,"time_range_node_id":23,"width_ms":60000}],"stored_outputs":[]},"node_id":24,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3780000},{"included":-3720000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3720000,"scan_node_id":0,"time_range_node_id":26,"width_ms":60000}],"stored_outputs":[]},"node_id":27,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3840000},{"included":-3780000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3780000,"scan_node_id":0,"time_range_node_id":29,"width_ms":60000}],"stored_outputs":[]},"node_id":30,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3900000},{"included":-3840000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3840000,"scan_node_id":0,"time_range_node_id":32,"width_ms":60000}],"stored_outputs":[]},"node_id":33,"retention_ms":3900000}]}, -{"name":"runtime_install a_coarse_sum_rolls_up_from_the_stored_fine_sum","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[1]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}}],"roots":[5,6],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"db0c9241a79202b6925e84aef010e89a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"3c90a6b5ff3ecaa445ea9bf285e1dc0b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, -{"name":"runtime_install a_kept_sliding_window_merge_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"NotApplicable"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"NotApplicable"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"NotApplicable"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":null,"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"materialization":{"MatAtQueryKeptAcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}}],"roots":[16],"scalar_roots":[]},"stored_outputs":[{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2,5,8,11,14]},"node_id":15,"retention_ms":3900000}]}, -{"name":"runtime_install a_summary_across_series_from_per_series_summaries_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":6,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":3}}],"qualifier":null}}}}],"roots":[5,7],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"5555de6812a18c62345c199d5ba8f06e","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"f35ee4e847802c130cbd5221a81f7ea1","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, -{"name":"runtime_install group_outputs_from_one_stored_per_series_sum_are_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":8,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":9,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":4,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":3,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":5,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":5}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":8,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":7,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"instance","expr":{"Column":3}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":9,"materialization":{"MatAtIngestion":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":8,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":10,"materialization":"NotMaterialized","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":9}}}}],"roots":[6,10],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"672f965318f2bf2ba350748044719b9b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"7976839b25e74a9cfac2ab1d6d01a63a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":5,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"84209f44520311bced823b9e98eaf85c","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":9,"retention_ms":60000}]} +{"name":"repeating p99-60m/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":18,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":34,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":33,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":35,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":34,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":36,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":37,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":36,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":38,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":37,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":39,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":40,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":39,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":41,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":40,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":42,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":43,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":42,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":44,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":43,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":45,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":46,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":45,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":47,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":46,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":48,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":49,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":48,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":50,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":49,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":51,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":52,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":51,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":53,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":52,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":35,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":38,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":41,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":44,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":47,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":50,"role":"Input","window":"NotApplicable"},{"consumer":54,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":53,"role":"Input","window":"NotApplicable"},{"consumer":55,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":54,"role":"Input","window":"NotApplicable"},{"consumer":56,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":55,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":200000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":400000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":600000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":800000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1000000}}}}},{"guarantee":null,"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":15,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":17,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":18,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1200000}}}}},{"guarantee":null,"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":18,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":20,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":19,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":21,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1400000}}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":21,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":23,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":22,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":24,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1600000}}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":24,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":26,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":25,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":27,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":1800000}}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":27,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":29,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":28,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":30,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2000000}}}}},{"guarantee":null,"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":30,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":32,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":31,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":33,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2200000}}}}},{"guarantee":null,"id":34,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":33,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":35,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":34,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":36,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2400000}}}}},{"guarantee":null,"id":37,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":36,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":38,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":37,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":39,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2600000}}}}},{"guarantee":null,"id":40,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":39,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":41,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":40,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":42,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":2800000}}}}},{"guarantee":null,"id":43,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":42,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":44,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":43,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":45,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3000000}}}}},{"guarantee":null,"id":46,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":45,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":47,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":46,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":48,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3200000}}}}},{"guarantee":null,"id":49,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":48,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":50,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":49,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":51,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3400000}}}}},{"guarantee":null,"id":52,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":51,"kind":"range","range":{"nanos":0,"secs":200}}}}},{"guarantee":null,"id":53,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":52,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":54,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53]}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":55,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"SummaryEstimate":{"query":{"Quantile":{"q":0.99}},"summary_input":54}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":56,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":55,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":2}}],"qualifier":null}}}}],"roots":[56],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-200000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":200000}],"stored_outputs":[]},"node_id":2,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-400000},{"included":-200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":200000,"scan_node_id":0,"time_range_node_id":4,"width_ms":200000}],"stored_outputs":[]},"node_id":5,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":400000,"scan_node_id":0,"time_range_node_id":7,"width_ms":200000}],"stored_outputs":[]},"node_id":8,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-800000},{"included":-600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":600000,"scan_node_id":0,"time_range_node_id":10,"width_ms":200000}],"stored_outputs":[]},"node_id":11,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1000000},{"included":-800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":800000,"scan_node_id":0,"time_range_node_id":13,"width_ms":200000}],"stored_outputs":[]},"node_id":14,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1200000},{"included":-1000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1000000,"scan_node_id":0,"time_range_node_id":16,"width_ms":200000}],"stored_outputs":[]},"node_id":17,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1400000},{"included":-1200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1200000,"scan_node_id":0,"time_range_node_id":19,"width_ms":200000}],"stored_outputs":[]},"node_id":20,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1600000},{"included":-1400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1400000,"scan_node_id":0,"time_range_node_id":22,"width_ms":200000}],"stored_outputs":[]},"node_id":23,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-1800000},{"included":-1600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1600000,"scan_node_id":0,"time_range_node_id":25,"width_ms":200000}],"stored_outputs":[]},"node_id":26,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2000000},{"included":-1800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":1800000,"scan_node_id":0,"time_range_node_id":28,"width_ms":200000}],"stored_outputs":[]},"node_id":29,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2200000},{"included":-2000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2000000,"scan_node_id":0,"time_range_node_id":31,"width_ms":200000}],"stored_outputs":[]},"node_id":32,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2400000},{"included":-2200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2200000,"scan_node_id":0,"time_range_node_id":34,"width_ms":200000}],"stored_outputs":[]},"node_id":35,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2600000},{"included":-2400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2400000,"scan_node_id":0,"time_range_node_id":37,"width_ms":200000}],"stored_outputs":[]},"node_id":38,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-2800000},{"included":-2600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2600000,"scan_node_id":0,"time_range_node_id":40,"width_ms":200000}],"stored_outputs":[]},"node_id":41,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3000000},{"included":-2800000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":2800000,"scan_node_id":0,"time_range_node_id":43,"width_ms":200000}],"stored_outputs":[]},"node_id":44,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3200000},{"included":-3000000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3000000,"scan_node_id":0,"time_range_node_id":46,"width_ms":200000}],"stored_outputs":[]},"node_id":47,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3400000},{"included":-3200000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3200000,"scan_node_id":0,"time_range_node_id":49,"width_ms":200000}],"stored_outputs":[]},"node_id":50,"retention_ms":3600000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-3600000},{"included":-3400000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3400000,"scan_node_id":0,"time_range_node_id":52,"width_ms":200000}],"stored_outputs":[]},"node_id":53,"retention_ms":3600000}]}, +{"name":"repeating offset-chain/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":17,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":18,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":32,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"NotApplicable"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":300000}}}}},{"guarantee":null,"id":2,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":1,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":3,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":2,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":360000}}}}},{"guarantee":null,"id":5,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":4,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":6,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":5,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":420000}}}}},{"guarantee":null,"id":8,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":7,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":9,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":8,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":480000}}}}},{"guarantee":null,"id":11,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":10,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":12,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":11,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":540000}}}}},{"guarantee":null,"id":14,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":13,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":15,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":14,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":600000}}}}},{"guarantee":null,"id":17,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":16,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":18,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":17,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":660000}}}}},{"guarantee":null,"id":20,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":19,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":21,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":20,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":720000}}}}},{"guarantee":null,"id":23,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":22,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":24,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":23,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":780000}}}}},{"guarantee":null,"id":26,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":25,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":27,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":26,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":840000}}}}},{"guarantee":null,"id":29,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":28,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":30,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":29,"family":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Sketch":[{"algorithm":"Kll","params":{"Kll":{"failure_probability":1e-05,"k":469}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[3,6,9,12,15,18,21,24,27,30]}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":32,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"quantile","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"SummaryEstimate":{"query":{"Quantile":{"q":0.99}},"summary_input":31}}}},{"guarantee":{"provenance":[{"algorithm":"Kll","contract":"apache_datasketches_kll_empirical_99_delta_scaled_a9b42755072b","kind":"sketch_evaluation","params":{"Kll":{"failure_probability":1e-05,"k":469}},"query":"Quantile { q: 0.99 }"}],"spec":{"accuracy_metric":"rank","accuracy_scope":"per_value","error":{"op":"constant","value":0.009954464416322084},"failure_probability":{"op":"constant","value":1e-05}}},"id":33,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":32,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":2}}],"qualifier":null}}}}],"roots":[33],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-360000},{"included":-300000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":300000,"scan_node_id":0,"time_range_node_id":2,"width_ms":60000}],"stored_outputs":[]},"node_id":3,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-420000},{"included":-360000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":360000,"scan_node_id":0,"time_range_node_id":5,"width_ms":60000}],"stored_outputs":[]},"node_id":6,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-480000},{"included":-420000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":420000,"scan_node_id":0,"time_range_node_id":8,"width_ms":60000}],"stored_outputs":[]},"node_id":9,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-540000},{"included":-480000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":480000,"scan_node_id":0,"time_range_node_id":11,"width_ms":60000}],"stored_outputs":[]},"node_id":12,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-540000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":540000,"scan_node_id":0,"time_range_node_id":14,"width_ms":60000}],"stored_outputs":[]},"node_id":15,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-660000},{"included":-600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":600000,"scan_node_id":0,"time_range_node_id":17,"width_ms":60000}],"stored_outputs":[]},"node_id":18,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-720000},{"included":-660000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":660000,"scan_node_id":0,"time_range_node_id":20,"width_ms":60000}],"stored_outputs":[]},"node_id":21,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-780000},{"included":-720000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":720000,"scan_node_id":0,"time_range_node_id":23,"width_ms":60000}],"stored_outputs":[]},"node_id":24,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-840000},{"included":-780000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":780000,"scan_node_id":0,"time_range_node_id":26,"width_ms":60000}],"stored_outputs":[]},"node_id":27,"retention_ms":900000},{"built_at":"ingestion_run","coverage":{"definition_id":"9f0c9036ac7789a53d65f287a16aad22","selection":[{"columns":[],"relative_time":[{"excluded":-900000},{"included":-840000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":840000,"scan_node_id":0,"time_range_node_id":29,"width_ms":60000}],"stored_outputs":[]},"node_id":30,"retention_ms":900000}]}, +{"name":"repeating rollup/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":15,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":18,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":21,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":24,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":27,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":20,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":23,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":26,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":29,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":31,"role":"Input","window":"NotApplicable"},{"consumer":33,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":32,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":34,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":300000}}}}},{"guarantee":null,"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":15,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":17,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":18,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":360000}}}}},{"guarantee":null,"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":18,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":20,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":19,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":21,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":420000}}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":21,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":23,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":22,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":24,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":480000}}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":24,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":26,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":25,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":27,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":540000}}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":27,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":29,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":28,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":30,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14,17,20,23,26,29]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":30}}}},{"guarantee":null,"id":32,"lifetime":{"OneEvaluation":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":31,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":33,"lifetime":{"OneEvaluation":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":32}}}},{"guarantee":null,"id":34,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":33,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}}],"roots":[33,35],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-360000},{"included":-300000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":300000,"scan_node_id":0,"time_range_node_id":16,"width_ms":60000}],"stored_outputs":[]},"node_id":17,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-420000},{"included":-360000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":360000,"scan_node_id":0,"time_range_node_id":19,"width_ms":60000}],"stored_outputs":[]},"node_id":20,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-480000},{"included":-420000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":420000,"scan_node_id":0,"time_range_node_id":22,"width_ms":60000}],"stored_outputs":[]},"node_id":23,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-540000},{"included":-480000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":480000,"scan_node_id":0,"time_range_node_id":25,"width_ms":60000}],"stored_outputs":[]},"node_id":26,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-540000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":540000,"scan_node_id":0,"time_range_node_id":28,"width_ms":60000}],"stored_outputs":[]},"node_id":29,"retention_ms":600000}]}, +{"name":"repeating rate-5m/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"NotApplicable"},{"consumer":18,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":34,"role":"Input","window":"NotApplicable"},{"consumer":36,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":35,"role":"Input","window":"NotApplicable"},{"consumer":37,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":36,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}},{"guarantee":null,"id":17,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":18,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":17}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3600000}}}}},{"guarantee":null,"id":20,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":19,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":21,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":20,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3660000}}}}},{"guarantee":null,"id":23,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":22,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":24,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":23,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3720000}}}}},{"guarantee":null,"id":26,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":25,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":27,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":26,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3780000}}}}},{"guarantee":null,"id":29,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":28,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":30,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":29,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3840000}}}}},{"guarantee":null,"id":32,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":31,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":33,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":32,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":34,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[21,24,27,30,33]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}},{"guarantee":null,"id":36,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":35,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":37,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":36}}}}],"roots":[18,37],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3660000},{"included":-3600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3600000,"scan_node_id":0,"time_range_node_id":20,"width_ms":60000}],"stored_outputs":[]},"node_id":21,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3720000},{"included":-3660000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3660000,"scan_node_id":0,"time_range_node_id":23,"width_ms":60000}],"stored_outputs":[]},"node_id":24,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3780000},{"included":-3720000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3720000,"scan_node_id":0,"time_range_node_id":26,"width_ms":60000}],"stored_outputs":[]},"node_id":27,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3840000},{"included":-3780000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3780000,"scan_node_id":0,"time_range_node_id":29,"width_ms":60000}],"stored_outputs":[]},"node_id":30,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3900000},{"included":-3840000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3840000,"scan_node_id":0,"time_range_node_id":32,"width_ms":60000}],"stored_outputs":[]},"node_id":33,"retention_ms":3900000}]}, +{"name":"runtime_install a_coarse_sum_rolls_up_from_the_stored_fine_sum","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[1]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}}],"roots":[5,6],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"db0c9241a79202b6925e84aef010e89a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"3c90a6b5ff3ecaa445ea9bf285e1dc0b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, +{"name":"runtime_install a_kept_sliding_window_merge_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"NotApplicable"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"NotApplicable"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"NotApplicable"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}}],"roots":[16],"scalar_roots":[]},"stored_outputs":[{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2,5,8,11,14]},"node_id":15,"retention_ms":3900000}]}, +{"name":"runtime_install a_summary_across_series_from_per_series_summaries_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":6,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":3}}],"qualifier":null}}}}],"roots":[5,7],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"5555de6812a18c62345c199d5ba8f06e","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"f35ee4e847802c130cbd5221a81f7ea1","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, +{"name":"runtime_install group_outputs_from_one_stored_per_series_sum_are_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":8,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":9,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":3,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":5}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":8,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":7,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"instance","expr":{"Column":3}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":9,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":8,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":9}}}}],"roots":[6,10],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"672f965318f2bf2ba350748044719b9b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"7976839b25e74a9cfac2ab1d6d01a63a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":5,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"84209f44520311bced823b9e98eaf85c","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":9,"retention_ms":60000}]} ] diff --git a/tools/dag-viewer/test-fixtures/memo-enumeration-small.json b/tools/dag-viewer/test-fixtures/memo-enumeration-small.json index 633a16fa6..c14b9d9ce 100644 --- a/tools/dag-viewer/test-fixtures/memo-enumeration-small.json +++ b/tools/dag-viewer/test-fixtures/memo-enumeration-small.json @@ -1 +1 @@ -{"memo":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":4,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":9,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":10}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":12}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":13,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":15}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":16,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":18}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":19,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null}],"steps":[{"step":"stage0","title":"Stage 0","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":3},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":4},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":5}]},{"step":"pass1","title":"Stage 1, Pass 1","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[0],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan http_requests_total","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[1],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[2],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"rate per series","group_of_node":{"1":1},"node":2}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[3],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"sum by (job)","group_of_node":{"2":2},"node":3}],"node":3},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[4],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan http_requests_total","group_of_node":{},"node":0}],"node":0},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[5],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":4},"node":1}],"node":1},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[6],"children":[5],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"sum_over_time per series","group_of_node":{"1":5},"node":4}],"node":4},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":4,"candidate_count_by_origin":{"pass1":3,"shared_build":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact accumulator","group_of_node":{"4":6},"node":5},{"index":1,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CMS+heap","group_of_node":{"4":6},"node":5},{"index":2,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CountSketch+heap","group_of_node":{"4":6},"node":5},{"index":3,"implements":[7],"children":[6],"origin":"shared_build","accuracy_budget_parts":0.5,"added":true,"label":"CMS+heap shared build","group_of_node":{"4":6},"node":5}],"node":5}]}],"selected_choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"enumeration":{"step":"pass1","per_step":{"stage0":{"count":1,"complete":true},"pass1":{"count":4,"complete":true}},"limit":1000,"choices":[{"id":"E1","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0},"accuracy_budget_parts_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":3.0,"cheaper_than_selected":false,"roots":[11,14]},{"id":"E2","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"accuracy_budget_parts_1":true,"selected":true,"valid":true,"rejection":null,"cost_per_second":2.0,"cheaper_than_selected":false,"roots":[11,17]},{"id":"E3","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":2},"accuracy_budget_parts_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":1.5,"cheaper_than_selected":true,"roots":[11,20]},{"id":"E4","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":3},"accuracy_budget_parts_1":false,"selected":false,"valid":false,"rejection":"accuracy_target_missed","cost_per_second":null,"cheaper_than_selected":false,"roots":[11,17]}],"priced":{"count":4,"cheaper_than_selected":1,"selected_cost_per_second":2.0}}}} +{"memo":{"nodes":[{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":4,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":9,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":10}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":12}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":13,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":15}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Project":{"child":16,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":7,"family":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":18}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Project":{"child":19,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null}],"steps":[{"step":"stage0","title":"Stage 0","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":3},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":4},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":5}]},{"step":"pass1","title":"Stage 1, Pass 1","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[0],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan http_requests_total","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[1],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[2],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"rate per series","group_of_node":{"1":1},"node":2}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[3],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"sum by (job)","group_of_node":{"2":2},"node":3}],"node":3},{"id":4,"label":"Scan http_requests_total","children":[],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[4],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan http_requests_total","group_of_node":{},"node":0}],"node":0},{"id":5,"label":"TimeRange 1m","children":[4],"parents":[6],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[5],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":4},"node":1}],"node":1},{"id":6,"label":"sum_over_time per series","children":[5],"parents":[7],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[6],"children":[5],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"sum_over_time per series","group_of_node":{"1":5},"node":4}],"node":4},{"id":7,"label":"topk by (job) 10","children":[6],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":4,"candidate_count_by_origin":{"pass1":3,"shared_build":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact accumulator","group_of_node":{"4":6},"node":5},{"index":1,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CMS+heap","group_of_node":{"4":6},"node":5},{"index":2,"implements":[7],"children":[6],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CountSketch+heap","group_of_node":{"4":6},"node":5},{"index":3,"implements":[7],"children":[6],"origin":"shared_build","accuracy_budget_parts":0.5,"added":true,"label":"CMS+heap shared build","group_of_node":{"4":6},"node":5}],"node":5}]}],"selected_choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"enumeration":{"step":"pass1","per_step":{"stage0":{"count":1,"complete":true},"pass1":{"count":4,"complete":true}},"limit":1000,"choices":[{"id":"E1","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0},"accuracy_budget_parts_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":3.0,"cheaper_than_selected":false,"roots":[11,14]},{"id":"E2","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1},"accuracy_budget_parts_1":true,"selected":true,"valid":true,"rejection":null,"cost_per_second":2.0,"cheaper_than_selected":false,"roots":[11,17]},{"id":"E3","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":2},"accuracy_budget_parts_1":true,"selected":false,"valid":true,"rejection":null,"cost_per_second":1.5,"cheaper_than_selected":true,"roots":[11,20]},{"id":"E4","choice":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":3},"accuracy_budget_parts_1":false,"selected":false,"valid":false,"rejection":"accuracy_target_missed","cost_per_second":null,"cheaper_than_selected":false,"roots":[11,17]}],"priced":{"count":4,"cheaper_than_selected":1,"selected_cost_per_second":2.0}}}} diff --git a/tools/dag-viewer/test-fixtures/memo-small.json b/tools/dag-viewer/test-fixtures/memo-small.json index cf7f96aea..9c32559d4 100644 --- a/tools/dag-viewer/test-fixtures/memo-small.json +++ b/tools/dag-viewer/test-fixtures/memo-small.json @@ -1 +1 @@ -{"memo":{"nodes":[{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Aggregate":{"child":4,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":6}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":2,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":10}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":11,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":13}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"NonASAP":{"Project":{"child":14,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryTumblingWindowChain":{"child":16,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"tumbling_window_count":6,"tumbling_window_width_ms":10000,"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryMerge":{"children":[17]}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"materialization":"NotMaterialized","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":18}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"materialization":"NotMaterialized","operator":{"ASAP":{"SummaryTumblingWindowChain":{"child":0,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"tumbling_window_count":6,"tumbling_window_width_ms":10000,"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"steps":[{"step":"stage0","title":"Stage 0","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0,1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":5}]},{"step":"pass1","title":"Stage 1, Pass 1","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":2,"candidate_count_by_origin":{"pass1":2},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact rate accumulator","group_of_node":{"1":1},"node":7},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate rate","group_of_node":{"1":1},"node":2}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":2,"candidate_count_by_origin":{"pass1":2},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate sum","group_of_node":{"2":2},"node":3},{"index":1,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact sum accumulator","group_of_node":{"2":2},"node":9}],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate sum_over_time","group_of_node":{"1":1},"node":4}],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":3,"candidate_count_by_origin":{"pass1":3},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate topk","group_of_node":{"4":4},"node":5},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CMS+heap depth 7 width 272","group_of_node":{"1":1},"node":12},{"index":2,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CountSketch+heap","group_of_node":{"1":1},"node":15}],"node":5}]},{"step":"pass2","title":"Stage 1, Pass 2","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1,6],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"Scan","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":20,"candidate_count_by_origin":{"pass1":2,"tumbling_windows":9,"shared_build":9},"candidates_capped":true,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact rate accumulator","group_of_node":{"1":1},"node":7},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate rate","group_of_node":{"1":1},"node":2},{"index":2,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 1","group_of_node":{"17":6},"node":19},{"index":3,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 2","group_of_node":{"17":6},"node":19},{"index":4,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 3","group_of_node":{"17":6},"node":19},{"index":5,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 4","group_of_node":{"17":6},"node":19},{"index":6,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 5","group_of_node":{"17":6},"node":19},{"index":7,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 6","group_of_node":{"17":6},"node":19},{"index":8,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 1","group_of_node":{"17":6},"node":19},{"index":9,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 2","group_of_node":{"17":6},"node":19},{"index":10,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 3","group_of_node":{"17":6},"node":19},{"index":11,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 4","group_of_node":{"17":6},"node":19},{"index":12,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 5","group_of_node":{"17":6},"node":19}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":3,"candidate_count_by_origin":{"pass1":2,"rollup":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate sum","group_of_node":{"2":2},"node":3},{"index":1,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact sum accumulator","group_of_node":{"2":2},"node":9},{"index":2,"implements":[],"children":[2],"origin":"rollup","accuracy_budget_parts":1,"added":true,"label":"sum by (job) rolled up from G2's accumulator","group_of_node":{"2":2},"node":9}],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate sum_over_time","group_of_node":{"1":1},"node":4}],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":3,"candidate_count_by_origin":{"pass1":3},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate topk","group_of_node":{"4":4},"node":5},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"CMS+heap depth 7 width 272","group_of_node":{"1":1},"node":12},{"index":2,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"CountSketch+heap","group_of_node":{"1":1},"node":15}],"node":5},{"id":6,"label":"SummaryTumblingWindowChain 6 × 10 s","children":[0],"parents":[],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"shared_build":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"SummaryTumblingWindowChain 6 × 10 s, rate accumulator","group_of_node":{"0":0},"node":20}],"node":17}]}],"selected_choice":{"5":1,"3":0,"2":2,"6":0,"1":0,"0":0,"4":0}}} +{"memo":{"nodes":[{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}},"result_kind":"range_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"kind":"rate"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":2,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":1,"filters":[],"having":null,"measures":[{"col":null,"kind":"sum"}],"output_names":[""],"reduction":"PerEntity"}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Aggregate":{"child":4,"filters":[],"having":null,"measures":[{"accuracy":{"accuracy_scope":"whole_result","failure_probability":0.001,"max_error":0.01},"k":10,"kind":"top_k"}],"output_names":[],"reduction":{"Reduce":[2]}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"topk_10","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":6}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":2,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":8}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CmsWithHeap","category":"TopK","params":{"CmsWithHeap":{"depth":7,"heap_size":100,"width":272}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":10}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Project":{"child":11,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryAgg":{"child":1,"family":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":{"Column":{"Named":"$promql_series_identity"}},"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"samples_of_metric","metric":"http_requests_total"}},"reduction":{"Reduce":[2]}}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Sketch":[{"algorithm":"CountSketchWithHeap","category":"TopK","params":{"CountSketchWithHeap":{"depth":81,"heap_size":100,"width":30000}}},"PerSubpopulationInstance"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryEstimate":{"query":{"TopK":{"k":10}},"summary_input":13}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"topk","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"NonASAP":{"Project":{"child":14,"cols":[{"alias":"job","expr":{"Column":0}},{"alias":"topk_10","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":1}}],"qualifier":null}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"topk_10","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"http_requests_total"}}}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryTumblingWindowChain":{"child":16,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"tumbling_window_count":6,"tumbling_window_width_ms":10000,"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryMerge":{"children":[17]}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"lifetime":"None","operator":{"ASAP":{"FinalizeExactAccumulator":{"child":18}}},"result_kind":"instant_vector","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null},{"guarantee":null,"lifetime":"None","operator":{"ASAP":{"SummaryTumblingWindowChain":{"child":0,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"tumbling_window_count":6,"tumbling_window_width_ms":10000,"reduction":"PerEntity"}}},"result_kind":"state","schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"timing":null}],"steps":[{"step":"stage0","title":"Stage 0","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0,1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":0,"candidate_count_by_origin":{},"candidates_capped":false,"candidates":[],"node":5}]},{"step":"pass1","title":"Stage 1, Pass 1","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"Scan","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":2,"candidate_count_by_origin":{"pass1":2},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact rate accumulator","group_of_node":{"1":1},"node":7},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate rate","group_of_node":{"1":1},"node":2}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":2,"candidate_count_by_origin":{"pass1":2},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate sum","group_of_node":{"2":2},"node":3},{"index":1,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact sum accumulator","group_of_node":{"2":2},"node":9}],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate sum_over_time","group_of_node":{"1":1},"node":4}],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":3,"candidate_count_by_origin":{"pass1":3},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"exact Aggregate topk","group_of_node":{"4":4},"node":5},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CMS+heap depth 7 width 272","group_of_node":{"1":1},"node":12},{"index":2,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":true,"label":"CountSketch+heap","group_of_node":{"1":1},"node":15}],"node":5}]},{"step":"pass2","title":"Stage 1, Pass 2","groups":[{"id":0,"label":"Scan http_requests_total","children":[],"parents":[1,6],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"Scan","group_of_node":{},"node":0}],"node":0},{"id":1,"label":"TimeRange 1m","children":[0],"parents":[2,4],"queries":[0,1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"TimeRange 1m","group_of_node":{"0":0},"node":1}],"node":1},{"id":2,"label":"rate per series","children":[1],"parents":[3],"queries":[0],"roots_of":[],"candidate_count":20,"candidate_count_by_origin":{"pass1":2,"tumbling_windows":9,"shared_build":9},"candidates_capped":true,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact rate accumulator","group_of_node":{"1":1},"node":7},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate rate","group_of_node":{"1":1},"node":2},{"index":2,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 1","group_of_node":{"17":6},"node":19},{"index":3,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 2","group_of_node":{"17":6},"node":19},{"index":4,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 3","group_of_node":{"17":6},"node":19},{"index":5,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 4","group_of_node":{"17":6},"node":19},{"index":6,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 5","group_of_node":{"17":6},"node":19},{"index":7,"implements":[],"children":[6],"origin":"tumbling_windows","accuracy_budget_parts":1,"added":true,"label":"rate accumulator over G6's panes, variant 6","group_of_node":{"17":6},"node":19},{"index":8,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 1","group_of_node":{"17":6},"node":19},{"index":9,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 2","group_of_node":{"17":6},"node":19},{"index":10,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 3","group_of_node":{"17":6},"node":19},{"index":11,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 4","group_of_node":{"17":6},"node":19},{"index":12,"implements":[],"children":[6],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"rate accumulator read from shared build, variant 5","group_of_node":{"17":6},"node":19}],"node":2},{"id":3,"label":"sum by (job)","children":[2],"parents":[],"queries":[0],"roots_of":[0],"candidate_count":3,"candidate_count_by_origin":{"pass1":2,"rollup":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate sum","group_of_node":{"2":2},"node":3},{"index":1,"implements":[],"children":[2],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact sum accumulator","group_of_node":{"2":2},"node":9},{"index":2,"implements":[],"children":[2],"origin":"rollup","accuracy_budget_parts":1,"added":true,"label":"sum by (job) rolled up from G2's accumulator","group_of_node":{"2":2},"node":9}],"node":3},{"id":4,"label":"sum_over_time per series","children":[1],"parents":[5],"queries":[1],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"pass1":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate sum_over_time","group_of_node":{"1":1},"node":4}],"node":4},{"id":5,"label":"topk 10 by (job)","children":[4],"parents":[],"queries":[1],"roots_of":[1],"candidate_count":3,"candidate_count_by_origin":{"pass1":3},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[4],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"exact Aggregate topk","group_of_node":{"4":4},"node":5},{"index":1,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"CMS+heap depth 7 width 272","group_of_node":{"1":1},"node":12},{"index":2,"implements":[],"children":[1],"origin":"pass1","accuracy_budget_parts":1,"added":false,"label":"CountSketch+heap","group_of_node":{"1":1},"node":15}],"node":5},{"id":6,"label":"SummaryTumblingWindowChain 6 × 10 s","children":[0],"parents":[],"queries":[0],"roots_of":[],"candidate_count":1,"candidate_count_by_origin":{"shared_build":1},"candidates_capped":false,"candidates":[{"index":0,"implements":[],"children":[0],"origin":"shared_build","accuracy_budget_parts":1,"added":true,"label":"SummaryTumblingWindowChain 6 × 10 s, rate accumulator","group_of_node":{"0":0},"node":20}],"node":17}]}],"selected_choice":{"5":1,"3":0,"2":2,"6":0,"1":0,"0":0,"4":0}}} From bca3b77967a59ffa53b529d1538a75144b98ade2 Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Wed, 4 Nov 2026 23:51:00 +0000 Subject: [PATCH 3/9] refactor: rename what held the old enum's values to say what it holds MaterializationAssignment -> PhysicalPropertiesAssignment, apply_materialization_timings(_to_roots) -> apply_physical_properties(_to_roots), MaterializationCandidate -> KeptOutputCandidate (find_kept_output_candidates), SummaryMaterializationEligibility -> SummaryKeepEligibility, ChooseMaterialization -> ChoosePhysicalProperties, MaterializationConflictsWithFixedTiming -> PhysicalPropertiesConflictWithFixedTiming, is_materialization_point -> is_keepable_state_output, HighestSharedQueryMaterialization -> HighestSharedOneEvaluation, materialize_selected_candidates -> realize_selected_candidates, and test names and files that said materialization / not_materialized. Docs, including planner-layering Algorithm 3 and the Example 1-4 acceptance docs, use (timing, lifetime) for the old enum's values. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/tests/ingestion_refresh_runs.rs | 8 +- crates/devtools/src/bin/asap_planner.rs | 4 +- crates/devtools/src/candidate_labels.rs | 2 +- crates/devtools/src/memo_pricing.rs | 6 +- crates/devtools/src/planner_fuzz/README.md | 2 +- crates/devtools/src/planner_fuzz/mod.rs | 2 +- crates/executor/src/physical_planner/mod.rs | 8 +- crates/executor/tests/common/mod.rs | 6 +- crates/executor/tests/time_series_window.rs | 8 +- .../executor/tests/weighted_topk_binding.rs | 8 +- crates/frontend-promql/tests/support.rs | 10 +- crates/frontend-sql/tests/pearson_corr.rs | 8 +- crates/integration-tests/src/lib.rs | 13 +- .../tests/frequency_execution.rs | 8 +- .../tests/kll_tumbling_window_execution.rs | 8 +- crates/integration-tests/tests/main.rs | 2 +- .../tests/per_series_exact_execution.rs | 8 +- .../tests/physical_common/mod.rs | 11 +- ...tion_e2e.rs => physical_properties_e2e.rs} | 32 +- .../tests/planner_layering_common/mod.rs | 21 +- .../tests/planner_layering_example1.rs | 4 +- .../tests/planner_layering_example2.rs | 4 +- .../tests/planner_layering_example4.rs | 6 +- .../tests/production_rollup_workloads.rs | 2 +- .../tests/promql_to_post_asap.rs | 2 +- crates/integration-tests/tests/reuse_rules.rs | 8 +- .../tests/runtime_handoff.rs | 2 +- .../tests/tumbling_window_merge.rs | 21 +- .../src/stage0/cse.rs | 2 +- .../src/test_support.rs | 14 +- .../src/catalog/configurations.rs | 27 +- .../src/catalog/mod.rs | 8 +- .../src/catalog/realize.rs | 20 +- crates/physical-asap-optimization/src/lib.rs | 309 +++++++++--------- .../src/split_by_timing.rs | 38 +-- crates/plan-selection/src/groups.rs | 2 +- .../src/groups/accuracy_positions.rs | 2 +- crates/plan-selection/src/lib.rs | 27 +- crates/plan-selection/src/milp/model.rs | 6 +- crates/plan-selection/src/milp/model/tests.rs | 2 +- crates/plan-selection/src/milp/warm_start.rs | 2 +- crates/planner/src/installable.rs | 20 +- crates/planner/src/pass.rs | 8 +- crates/planner/tests/runtime_install.rs | 8 +- crates/types/src/ir/mod.rs | 4 +- crates/types/src/ir/operator/node.rs | 2 +- crates/types/src/ir/physical_export.rs | 16 +- .../src/ir/properties/execution_data_state.rs | 8 +- crates/types/src/ir/properties/mod.rs | 2 +- .../src/ir/properties/summary_coverage.rs | 2 +- crates/types/src/ir/properties/timing.rs | 175 +++++----- crates/types/src/physical/workload_plan.rs | 4 +- crates/types/src/stages/physical/graph.rs | 10 +- crates/types/tests/materialized_view.rs | 38 +-- crates/types/tests/physical_export.rs | 34 +- crates/types/tests/schema_rebuilding.rs | 25 +- crates/types/tests/summary_merge_structure.rs | 20 +- crates/types/tests/tumbling_window_chain.rs | 8 +- .../architecture/input-output-workflow.md | 2 +- .../architecture/physical-plan-integration.md | 4 +- ...d_interface_with_pluggable_optimization.md | 2 +- docs/design_docs/concepts/post-asap-ir.md | 14 +- .../physical-planning-and-deployment.md | 8 +- .../maintained-populations.md | 4 +- .../proposals/joint-planning-search.md | 16 +- .../planner-layering-example1-acceptance.md | 36 +- .../planner-layering-example2-acceptance.md | 14 +- .../planner-layering-example3-acceptance.md | 4 +- .../planner-layering-example4-acceptance.md | 20 +- .../design_docs/proposals/planner-layering.md | 16 +- .../window-materialization-choices.md | 2 +- .../asap-aware-mapping-architecture.md | 8 +- .../asap-aware-mapping-contracts.md | 4 +- .../develop_docs/extend-asap-aware-mapping.md | 6 +- docs/develop_docs/library-api.md | 4 +- .../develop_docs/physical-compile-coverage.md | 2 +- docs/develop_docs/pre-asap-ir.md | 6 +- .../target-candidate-api-migration.md | 2 +- ...ng-window-search-compression-evaluation.md | 2 +- 79 files changed, 600 insertions(+), 643 deletions(-) rename crates/integration-tests/tests/{materialization_e2e.rs => physical_properties_e2e.rs} (93%) diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index 1751a7d87..6931a6f3f 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -16,8 +16,8 @@ use asap_types::ir::schema::{ SketchParams, SummaryUpdate, }; use asap_types::ir::{ - apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, NonASAPOp, Operator, - OperatorNode, QueryRoot, TimeRangeKind, + apply_physical_properties_to_roots, ASAPOp, NonASAPOp, Operator, OperatorNode, + PhysicalPropertiesAssignment, QueryRoot, TimeRangeKind, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::workload::{QueryRecurrence, RepeatedDemand, RepetitionInterval}; @@ -77,7 +77,7 @@ fn chain( /// kept with `kept` (`None`: not kept): the DAG Stage 3 costs, chains /// unexpanded. fn dag_of(summaries: &[Rc], kept: Option) -> PhysicalASAPDAG { - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); let roots: Vec = summaries .iter() .map(|summary| { @@ -94,7 +94,7 @@ fn dag_of(summaries: &[Rc], kept: Option) -> P ) }) .collect(); - let timed = apply_materialization_timings_to_roots(&roots, &assignment).unwrap(); + let timed = apply_physical_properties_to_roots(&roots, &assignment).unwrap(); compile_physical_asap_workload(&timed).unwrap() } diff --git a/crates/devtools/src/bin/asap_planner.rs b/crates/devtools/src/bin/asap_planner.rs index 916daa183..3aebed273 100644 --- a/crates/devtools/src/bin/asap_planner.rs +++ b/crates/devtools/src/bin/asap_planner.rs @@ -59,7 +59,7 @@ // - stage2_physical_asap_optimization (from `stage2`): `pruned_candidates`, // the physical candidates Stage 2 pruned (each with its memo `group`, // `operator_node`, `operator`, `implementation_root`, `timing`, -// `materialization` and `reason`); with `stage3`, `candidates` holds +// `lifetime` and `reason`); with `stage3`, `candidates` holds // `P1`, the selected plan as Stage 2 built it; // - stage3_plan_selection (from `stage3`): Stage 3's `Selection`: // `selected_dag` (`candidate_of_node`, `edges`, @@ -712,7 +712,7 @@ fn pass1_pruned_candidates_json(pass1: Option<&PerComputationLogicalMemoCandidat /// (`PhysicalASAPMemoCandidates::pruned_candidates`), in pruning order: /// each with its memo `group`, its `operator_node` (index into Stage 2's /// operator nodes), the node's `operator` label, whether it is an -/// `implementation_root`, its `timing` and `materialization`, and the +/// `implementation_root`, its `timing` and `lifetime`, and the /// `reason` (`PruneReason`, e.g. /// `RawDataNotRetained`). Empty without memo steps. fn stage2_pruned_candidates_json(stage2: Option<&PhysicalASAPMemoCandidates>) -> Vec { diff --git a/crates/devtools/src/candidate_labels.rs b/crates/devtools/src/candidate_labels.rs index 8164b3025..585345955 100644 --- a/crates/devtools/src/candidate_labels.rs +++ b/crates/devtools/src/candidate_labels.rs @@ -2,7 +2,7 @@ //! `asap_planner` viewer document and text //! only. Planning never reads them: they //! are pure functions of the candidates' planning data (the logical roots -//! and the materialization assignment). +//! and the physical properties assignment). use std::collections::BTreeMap; use std::rc::Rc; diff --git a/crates/devtools/src/memo_pricing.rs b/crates/devtools/src/memo_pricing.rs index 128cc4911..d099adf41 100644 --- a/crates/devtools/src/memo_pricing.rs +++ b/crates/devtools/src/memo_pricing.rs @@ -1,6 +1,6 @@ //! Price a memo's enumerated choices as the selected plan is priced: each //! choice's composed DAG (`memo::enumeration::build_logical_asap_dags_from_chosen_candidates`) goes through Stage 2 -//! (`optimize_physical_asap`, every materialization assignment) and Stage 3 +//! (`optimize_physical_asap`, every physical properties assignment) and Stage 3 //! (the reference pricer, `asap_plan_selection::reference_pricer`, under the //! run's models), and the plan it selects for //! it is installed as `plan_installable` installs one (`installable_plan_of`, @@ -181,7 +181,7 @@ fn price_choice( } /// Every physical plan Stage 2 offers for choice `index`'s composed `roots` -/// (each materialization assignment), named `E-`. +/// (each physical properties assignment), named `E-`. pub fn physical_plans_of( roots: &[QueryRoot], index: usize, @@ -255,7 +255,7 @@ pub struct EnumeratedChoice { /// The reference enumeration: the first `max_choices` choices of the /// Pass 2 memo (`run.logical_asap_candidates`), each composed, -/// implemented by Stage 2 with every materialization assignment, and all +/// implemented by Stage 2 with every physical properties assignment, and all /// their physical plans priced together by the reference pricer. #[derive(Debug)] pub struct ReferenceEnumeration { diff --git a/crates/devtools/src/planner_fuzz/README.md b/crates/devtools/src/planner_fuzz/README.md index 3370fa96f..044dbf232 100644 --- a/crates/devtools/src/planner_fuzz/README.md +++ b/crates/devtools/src/planner_fuzz/README.md @@ -106,7 +106,7 @@ derive_cost = cost(witness) − cost(W's plan) never from a guess: 1. Stage 2 and Stage 3 implement and price the witness the same way they price - any candidate. Each materialization assignment goes through + any candidate. Each physical properties assignment goes through `optimize_physical_asap` and `select_plan`, using the same cost model, deployment capabilities and accuracy checks as the search. The cheapest assignment is kept. 2. `W`'s selected logical plan is priced the same way. This gives the witness diff --git a/crates/devtools/src/planner_fuzz/mod.rs b/crates/devtools/src/planner_fuzz/mod.rs index e37b85e75..1668399b5 100644 --- a/crates/devtools/src/planner_fuzz/mod.rs +++ b/crates/devtools/src/planner_fuzz/mod.rs @@ -368,7 +368,7 @@ pub struct Planned { } /// A plan priced by Stage 2 and Stage 3 outside the search: the cheapest -/// materialization assignment of given logical roots. +/// physical properties assignment of given logical roots. #[derive(Debug, Clone, PartialEq, Serialize)] pub struct Priced { pub selected: String, diff --git a/crates/executor/src/physical_planner/mod.rs b/crates/executor/src/physical_planner/mod.rs index 55c37ff74..aa2d7f83d 100644 --- a/crates/executor/src/physical_planner/mod.rs +++ b/crates/executor/src/physical_planner/mod.rs @@ -1607,8 +1607,8 @@ mod compilation_tests { use planner_types::ir::physical_export::compile_physical_asap_workload; use planner_types::ir::schema::{Field, Schema}; use planner_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, - Operator, QueryRoot, + apply_physical_properties, NodeToTimedNodeCache, Operator, + PhysicalPropertiesAssignment, QueryRoot, }; let minute_ms = 60_000; let scan = OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { @@ -1650,9 +1650,9 @@ mod compilation_tests { let roots: Vec<_> = windows .iter() .map(|window| { - let timed = apply_materialization_timings( + let timed = apply_physical_properties( window, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut cache, ) .unwrap(); diff --git a/crates/executor/tests/common/mod.rs b/crates/executor/tests/common/mod.rs index 857d76bf9..0d9ff5820 100644 --- a/crates/executor/tests/common/mod.rs +++ b/crates/executor/tests/common/mod.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use planner_types::ir::physical_export::PhysicalASAPDAG; use planner_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, OperatorNode, + apply_physical_properties, NodeToTimedNodeCache, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, }; use std::rc::Rc; @@ -9,9 +9,9 @@ use std::rc::Rc; pub fn compile_physical_asap_dag( root: &Rc, ) -> Result> { - let root = apply_materialization_timings( + let root = apply_physical_properties( root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::default(), )?; Ok(planner_types::ir::physical_export::compile_physical_asap_dag(&root)?) diff --git a/crates/executor/tests/time_series_window.rs b/crates/executor/tests/time_series_window.rs index 792a2881b..91bcd78f0 100644 --- a/crates/executor/tests/time_series_window.rs +++ b/crates/executor/tests/time_series_window.rs @@ -12,8 +12,8 @@ use planner_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAP use planner_types::ir::scalar::{CompareOpKind, ScalarValue}; use planner_types::ir::schema::{DataType, Field, Schema, PROMQL_SERIES_IDENTITY}; use planner_types::ir::{ - apply_materialization_timings, ExprSemantics, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, Operator, OperatorNode, Predicate, ScalarExpr, TimeRangeKind, + apply_physical_properties, ExprSemantics, NodeToTimedNodeCache, NonASAPOp, Operator, + OperatorNode, PhysicalPropertiesAssignment, Predicate, ScalarExpr, TimeRangeKind, }; use std::collections::BTreeMap; use std::sync::Arc; @@ -84,9 +84,9 @@ fn window_over_rows( child, })) .unwrap(); - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &range, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); diff --git a/crates/executor/tests/weighted_topk_binding.rs b/crates/executor/tests/weighted_topk_binding.rs index e3d23aa45..9208ea6da 100644 --- a/crates/executor/tests/weighted_topk_binding.rs +++ b/crates/executor/tests/weighted_topk_binding.rs @@ -275,8 +275,8 @@ fn rate_updates_cannot_enter_integer_heap_factory() { fn continuously_maintained_dag(candidate: &Rc) -> PhysicalASAPDAG { use planner_types::ir::properties::ExecutionTiming; use planner_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, - Operator as IrOperator, OperatorNode, + apply_physical_properties, NodeToTimedNodeCache, Operator as IrOperator, OperatorNode, + PhysicalPropertiesAssignment, }; use planner_types::physical::{Lifetime, Medium, PhysicalProperties}; fn unpinned(node: &Rc) -> Rc { @@ -291,7 +291,7 @@ fn continuously_maintained_dag(candidate: &Rc) Rc::new(copy) } let candidate = unpinned(candidate); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for node in OperatorNode::reachable(&candidate) { if matches!(node.operator, IrOperator::ASAP(ASAPOp::SummaryAgg { .. })) { assignment.set( @@ -305,7 +305,7 @@ fn continuously_maintained_dag(candidate: &Rc) } } let timed = - apply_materialization_timings(&candidate, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&candidate, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); planner_types::ir::physical_export::compile_physical_asap_dag(&timed).unwrap() } diff --git a/crates/frontend-promql/tests/support.rs b/crates/frontend-promql/tests/support.rs index 19834b75d..715878589 100644 --- a/crates/frontend-promql/tests/support.rs +++ b/crates/frontend-promql/tests/support.rs @@ -76,7 +76,7 @@ pub fn promql_scalar(node: &ScalarExpr) -> Option { } } -/// Time `root` under the default materialization assignment (every summary +/// Time `root` under the default physical properties assignment (every summary /// at query time) and export the physical DAG — export needs every node /// timed first. #[allow(dead_code)] @@ -84,14 +84,14 @@ pub fn physical_asap_dag( root: &Rc, ) -> asap_types::ir::physical_export::PhysicalASAPDAG { use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; - let timed = apply_materialization_timings( + let timed = apply_physical_properties( root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) - .expect("default materialization timings"); + .expect("default physical properties"); asap_types::ir::physical_export::compile_physical_asap_dag(&timed) .expect("post-ASAP DAG export") } diff --git a/crates/frontend-sql/tests/pearson_corr.rs b/crates/frontend-sql/tests/pearson_corr.rs index c6f31079a..143dcba11 100644 --- a/crates/frontend-sql/tests/pearson_corr.rs +++ b/crates/frontend-sql/tests/pearson_corr.rs @@ -6,8 +6,8 @@ use asap_types::ir::operator::AggIntent; use asap_types::ir::properties::AccuracyTarget; use asap_types::ir::schema::{DataType, Field, Schema}; use asap_types::ir::{ - apply_materialization_timings, physical_export::compile_physical_asap_dag, - MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, OperatorNode, ScalarExpr, + apply_physical_properties, physical_export::compile_physical_asap_dag, NodeToTimedNodeCache, + NonASAPOp, OperatorNode, PhysicalPropertiesAssignment, ScalarExpr, }; fn catalog() -> SqlCatalog { @@ -179,9 +179,9 @@ async fn corr_survives_exact_plan_compilation() { // operator DAG, no ASAP node added. assert!(!plan.contains_asap(), "expected the exact plan"); assert_eq!(aggregate(plan).0, aggregate(&query).0); - let timed = apply_materialization_timings( + let timed = apply_physical_properties( plan, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs index 104a1f28e..84b2c974b 100644 --- a/crates/integration-tests/src/lib.rs +++ b/crates/integration-tests/src/lib.rs @@ -100,8 +100,7 @@ pub mod physical_export { use asap_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAPDAG}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, - OperatorNode, + apply_physical_properties, NodeToTimedNodeCache, OperatorNode, PhysicalPropertiesAssignment, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; @@ -109,7 +108,7 @@ pub mod physical_export { /// Time `root` under the default assignment (no sub-DAG kept, so every /// summary computed at query time). Returns the timed copy; read `node.timing` on it. pub fn timed(root: &Rc) -> Rc { - timed_with(root, &MaterializationAssignment::default()) + timed_with(root, &PhysicalPropertiesAssignment::default()) } /// Time `root` with every sub-DAG kept at ingestion time where the DAG @@ -117,7 +116,7 @@ pub mod physical_export { pub fn at_ingestion(root: &Rc) -> Rc { timed_with( root, - &MaterializationAssignment::with_default( + &PhysicalPropertiesAssignment::with_default( PhysicalProperties::new( ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory), @@ -129,10 +128,10 @@ pub mod physical_export { fn timed_with( root: &Rc, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, ) -> Rc { - apply_materialization_timings(root, assignment, &mut NodeToTimedNodeCache::new()) - .expect("materialization timing failed") + apply_physical_properties(root, assignment, &mut NodeToTimedNodeCache::new()) + .expect("applying physical properties failed") } /// Time `root` (default assignment), then export the physical DAG. diff --git a/crates/integration-tests/tests/frequency_execution.rs b/crates/integration-tests/tests/frequency_execution.rs index 24c083091..f48adf2c6 100644 --- a/crates/integration-tests/tests/frequency_execution.rs +++ b/crates/integration-tests/tests/frequency_execution.rs @@ -14,8 +14,8 @@ use asap_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAPOpe use asap_types::ir::properties::AccuracyTarget; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm}; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, OperatorNode, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, OperatorNode, + PhysicalPropertiesAssignment, }; use crate::physical_common; @@ -36,9 +36,9 @@ fn built_family(candidate: &Rc) -> Option { /// Execute `candidate` at query time over `SAMPLES`, all inside the window. fn execute(candidate: &Rc) -> Vec { - let timed = apply_materialization_timings( + let timed = apply_physical_properties( candidate, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); diff --git a/crates/integration-tests/tests/kll_tumbling_window_execution.rs b/crates/integration-tests/tests/kll_tumbling_window_execution.rs index bc0ad0698..c81bfd754 100644 --- a/crates/integration-tests/tests/kll_tumbling_window_execution.rs +++ b/crates/integration-tests/tests/kll_tumbling_window_execution.rs @@ -22,8 +22,8 @@ use asap_types::ir::schema::{ SketchParams, SketchStatistic, SummaryUpdate, }; use asap_types::ir::{ - apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, NonASAPOp, - OperatorNode, QueryRoot, TimeRangeKind, + apply_physical_properties_to_roots, ASAPOp, NonASAPOp, OperatorNode, + PhysicalPropertiesAssignment, QueryRoot, TimeRangeKind, }; use futures::{executor::block_on, StreamExt}; use std::{ @@ -120,12 +120,12 @@ fn fixture() -> Fixture { query: SketchStatistic::Quantile { q }, })) }; - let roots = apply_materialization_timings_to_roots( + let roots = apply_physical_properties_to_roots( &[ QueryRoot::Operator(estimate(0.5)), QueryRoot::Operator(estimate(0.99)), ], - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), ) .unwrap(); let compiled = compile_physical_asap_workload_with_node_ids(&roots).unwrap(); diff --git a/crates/integration-tests/tests/main.rs b/crates/integration-tests/tests/main.rs index bf81ee35d..1818b0b4f 100644 --- a/crates/integration-tests/tests/main.rs +++ b/crates/integration-tests/tests/main.rs @@ -20,7 +20,6 @@ mod identical_exact_queries; mod independent_plan_seed; mod joint_search_equivalence; mod kll_tumbling_window_execution; -mod materialization_e2e; mod materialized_views; mod memo_enumeration; mod nested; @@ -28,6 +27,7 @@ mod operator_design_examples; mod operator_sharing; mod per_computation_candidates_sql; mod per_series_exact_execution; +mod physical_properties_e2e; mod planner_layering_example1; mod planner_layering_example2; mod planner_layering_example3; diff --git a/crates/integration-tests/tests/per_series_exact_execution.rs b/crates/integration-tests/tests/per_series_exact_execution.rs index e20fed25b..964449b2c 100644 --- a/crates/integration-tests/tests/per_series_exact_execution.rs +++ b/crates/integration-tests/tests/per_series_exact_execution.rs @@ -18,8 +18,8 @@ use asap_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAPOpe use asap_types::ir::properties::AccuracyTarget; use asap_types::ir::schema::{Schema, PROMQL_SERIES_IDENTITY}; use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, - OperatorNode, + apply_physical_properties, NodeToTimedNodeCache, NonASAPOp, OperatorNode, + PhysicalPropertiesAssignment, }; use futures::{executor::block_on, StreamExt}; @@ -96,9 +96,9 @@ fn series_labels(schema: &Schema, row: &[Value]) -> BTreeMap { /// Run `query`'s exact per-entity plan at query time over `samples`, bound /// at its `Scan` of `x`: each answered series' `instance` and value. fn execute(query: &str, samples: &[RawDataSample]) -> Vec<(String, f64)> { - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &per_entity_plan(query), - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); diff --git a/crates/integration-tests/tests/physical_common/mod.rs b/crates/integration-tests/tests/physical_common/mod.rs index 4a4b7e4c1..d6be3ab28 100644 --- a/crates/integration-tests/tests/physical_common/mod.rs +++ b/crates/integration-tests/tests/physical_common/mod.rs @@ -37,7 +37,10 @@ pub fn execute( pub fn compile_physical_asap_dag( root: &std::rc::Rc, ) -> Result> { - compile_with(root, &asap_types::ir::MaterializationAssignment::default()) + compile_with( + root, + &asap_types::ir::PhysicalPropertiesAssignment::default(), + ) } /// As [`compile_physical_asap_dag`], with every sub-DAG kept at ingestion time @@ -48,7 +51,7 @@ pub fn compile_at_ingestion_physical_asap_dag( ) -> Result> { compile_with( root, - &asap_types::ir::MaterializationAssignment::with_default( + &asap_types::ir::PhysicalPropertiesAssignment::with_default( asap_types::physical::PhysicalProperties::new( asap_types::ir::properties::ExecutionTiming::IngestionTime, asap_types::physical::Lifetime::AcrossEvaluations( @@ -62,10 +65,10 @@ pub fn compile_at_ingestion_physical_asap_dag( fn compile_with( root: &std::rc::Rc, - assignment: &asap_types::ir::MaterializationAssignment, + assignment: &asap_types::ir::PhysicalPropertiesAssignment, ) -> Result> { let root = - asap_types::ir::apply_materialization_timings(root, assignment, &mut Default::default())?; + asap_types::ir::apply_physical_properties(root, assignment, &mut Default::default())?; Ok(asap_types::ir::physical_export::compile_physical_asap_dag( &root, )?) diff --git a/crates/integration-tests/tests/materialization_e2e.rs b/crates/integration-tests/tests/physical_properties_e2e.rs similarity index 93% rename from crates/integration-tests/tests/materialization_e2e.rs rename to crates/integration-tests/tests/physical_properties_e2e.rs index e782213e7..838712175 100644 --- a/crates/integration-tests/tests/materialization_e2e.rs +++ b/crates/integration-tests/tests/physical_properties_e2e.rs @@ -21,8 +21,8 @@ use asap_types::ir::physical_export::{ use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::properties::{AccuracyMetric, AccuracyTarget}; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, OperatorNode, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, OperatorNode, + PhysicalPropertiesAssignment, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; @@ -84,10 +84,10 @@ fn sketch_candidate(query: &str) -> Rc { /// The two placements under test: nothing stored, and every state stored at /// ingestion time where the DAG allows it. -fn placements() -> [MaterializationAssignment; 2] { +fn placements() -> [PhysicalPropertiesAssignment; 2] { [ - MaterializationAssignment::default(), - MaterializationAssignment::with_default(at_ingestion()), + PhysicalPropertiesAssignment::default(), + PhysicalPropertiesAssignment::with_default(at_ingestion()), ] } @@ -95,11 +95,13 @@ fn placements() -> [MaterializationAssignment; 2] { /// two timings (Pass 1 composes identical inputs as one memo group's node, /// e.g. the scan of two quantiles of one metric) is split first, one copy /// per timing. -fn timed_dag(root: &Rc, assignment: &MaterializationAssignment) -> PhysicalASAPDAG { +fn timed_dag( + root: &Rc, + assignment: &PhysicalPropertiesAssignment, +) -> PhysicalASAPDAG { let (split, assignment) = split_shared_by_timing(std::slice::from_ref(root), assignment); - let timed = - apply_materialization_timings(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); compile_physical_asap_dag(&timed).unwrap() } @@ -212,7 +214,7 @@ fn values_1_to_100(schema: &SchemaRef, _metric: &str) -> Batch { /// Not keeping it has no view and reads the raw source at /// query time; both answer alike. #[test] -fn materialization_decides_precompute_contents() { +fn physical_properties_decide_precompute_contents() { let root = sketch_candidate("quantile(0.99, latency)"); let mut answers = Vec::new(); for assignment in placements() { @@ -261,10 +263,10 @@ fn mixed_placement_answers_like_query_time() { 2, "two explicitly selected KLL builds" ); - let mut mixed = MaterializationAssignment::default(); + let mut mixed = PhysicalPropertiesAssignment::default(); mixed.set(&sketches(&root)[0], at_ingestion()); let mut answers = Vec::new(); - for assignment in [MaterializationAssignment::default(), mixed] { + for assignment in [PhysicalPropertiesAssignment::default(), mixed] { let dag = timed_dag(&root, &assignment); let ingestion = Scope::Ingestion { window_start_ms: 0, @@ -350,13 +352,13 @@ fn arithmetic_over_one_selector_executes() { ("m", "a", 290, 2.0), ("m", "b", 250, 5.0), ]; - let [not_materialized, at_ingestion] = placements().map(|a| timed_dag(&root, &a)); - assert!(!ingestion_binary(¬_materialized)); + let [not_kept, at_ingestion] = placements().map(|a| timed_dag(&root, &a)); + assert!(!ingestion_binary(¬_kept)); assert!( ingestion_binary(&at_ingestion), "one selector shares its key set" ); - for dag in [not_materialized, at_ingestion] { + for dag in [not_kept, at_ingestion] { let (values, _) = execute(&dag, &job_samples(&samples), INGESTION_WINDOW, 300_000); // job a: 3 + 3 = 6; job b: 5 + 5 = 10 (mispairing a with b gives 8 and 8). // KLL at epsilon 0.01 returns an input value within 0.01 of rank 0.9; diff --git a/crates/integration-tests/tests/planner_layering_common/mod.rs b/crates/integration-tests/tests/planner_layering_common/mod.rs index a51dadabe..0c5005657 100644 --- a/crates/integration-tests/tests/planner_layering_common/mod.rs +++ b/crates/integration-tests/tests/planner_layering_common/mod.rs @@ -659,27 +659,24 @@ pub fn assert_valid_and_uniquely_named(run: &Run) { /// No candidate is discarded before plan selection: physical ASAP-aware /// optimization gives each logical candidate `L` exactly one physical /// candidate with nothing materialized, `P`, and one `P-m` for each -/// other materialization assignment. -pub fn assert_one_unmaterialized_physical_candidate_per_logical(run: &Run) { +/// other physical properties assignment. +pub fn assert_one_not_kept_physical_candidate_per_logical(run: &Run) { assert!(run.pruned.is_empty(), "pruned: {:?}", run.pruned); - let unmaterialized: Vec<_> = run + let not_kept: Vec<_> = run .physical .iter() .filter(|p| !p.id.contains("-m")) .collect(); - let sources: BTreeSet<_> = unmaterialized - .iter() - .map(|p| p.from_logical.as_str()) - .collect(); + let sources: BTreeSet<_> = not_kept.iter().map(|p| p.from_logical.as_str()).collect(); let logical: BTreeSet<_> = run.logical.iter().map(|c| c.id.as_str()).collect(); assert_eq!(sources, logical); - assert_eq!(unmaterialized.len(), run.logical.len()); + assert_eq!(not_kept.len(), run.logical.len()); for p in &run.physical { let base = p.id.split("-m").next().unwrap(); assert_eq!(&base[1..], &p.from_logical[1..], "{}", p.id); - let unmaterialized = !p.id.contains("-m"); - assert_eq!(unmaterialized, !p.candidate.materializes_any(), "{}", p.id); - if unmaterialized { + let not_kept = !p.id.contains("-m"); + assert_eq!(not_kept, !p.candidate.materializes_any(), "{}", p.id); + if not_kept { for n in &p.dag().nodes { assert_eq!(keeping(p, n.id), Keeping::NotKept); } @@ -691,7 +688,7 @@ pub fn assert_one_unmaterialized_physical_candidate_per_logical(run: &Run) { /// The physical candidates with nothing materialized, one per logical /// candidate. -pub fn unmaterialized(run: &Run) -> impl Iterator { +pub fn not_kept(run: &Run) -> impl Iterator { run.physical .iter() .filter(|p| !p.candidate.materializes_any()) diff --git a/crates/integration-tests/tests/planner_layering_example1.rs b/crates/integration-tests/tests/planner_layering_example1.rs index fa9a37a5d..be2d8ac45 100644 --- a/crates/integration-tests/tests/planner_layering_example1.rs +++ b/crates/integration-tests/tests/planner_layering_example1.rs @@ -442,8 +442,8 @@ fn stage1_logical_asap_optimization_candidates_are_valid_and_uniquely_named() { #[test] fn stage2_physical_asap_optimization_keeps_every_logical_candidate() { let run = pipeline(); - assert_one_unmaterialized_physical_candidate_per_logical(&run); - let unshared = unmaterialized(&run) + assert_one_not_kept_physical_candidate_per_logical(&run); + let unshared = not_kept(&run) .filter(|p| whole_windows(p.dag()) && !classify(p.dag(), &p.query_roots).1) .count(); assert_eq!(unshared, 3); diff --git a/crates/integration-tests/tests/planner_layering_example2.rs b/crates/integration-tests/tests/planner_layering_example2.rs index 9c09da9fd..7f6114e35 100644 --- a/crates/integration-tests/tests/planner_layering_example2.rs +++ b/crates/integration-tests/tests/planner_layering_example2.rs @@ -661,10 +661,10 @@ fn stage1_logical_asap_optimization_candidates_are_valid_and_uniquely_named() { // ── Physical ASAP-aware optimization ───────────────────────────────────── -/// No candidate is discarded before plan selection: each logical candidate keeps one physical candidate with nothing materialized, plus one per other materialization assignment. +/// No candidate is discarded before plan selection: each logical candidate keeps one physical candidate with nothing materialized, plus one per other physical properties assignment. #[test] fn stage2_physical_asap_optimization_keeps_every_logical_candidate() { - assert_one_unmaterialized_physical_candidate_per_logical(&pipeline()); + assert_one_not_kept_physical_candidate_per_logical(&pipeline()); } /// Physical ASAP-aware optimization keeps the shared UnivMon as one build node read by all three queries. diff --git a/crates/integration-tests/tests/planner_layering_example4.rs b/crates/integration-tests/tests/planner_layering_example4.rs index 480d6ca98..52e62dd83 100644 --- a/crates/integration-tests/tests/planner_layering_example4.rs +++ b/crates/integration-tests/tests/planner_layering_example4.rs @@ -216,7 +216,7 @@ fn stage2_physical_asap_optimization_monthly_materialized_output_covers_its_cons /// The shared EH candidate yields A1 (query time, kept), A2 (ingestion time) and A3 (not materialized). #[test] #[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] -fn stage2_physical_asap_optimization_a_shared_eh_has_three_materialization_options() { +fn stage2_physical_asap_optimization_a_shared_eh_has_three_physical_properties_options() { let found: BTreeSet<_> = eh_options(&run_promql(&once())).into_keys().collect(); assert_eq!( found, @@ -315,7 +315,7 @@ fn keeping_query_time_results() -> DeploymentCapabilities { /// The 1-min tumbling KLL candidate yields B1 (ingestion time), B2 (not materialized) and B3 (query time, kept). #[test] -fn stage2_physical_asap_optimization_b_tumbling_kll_has_three_materialization_options() { +fn stage2_physical_asap_optimization_b_tumbling_kll_has_three_physical_properties_options() { let run = run_pattern_b_fixture( &pattern_b(), &CostInputs::default(), @@ -405,7 +405,7 @@ fn stage2_physical_asap_optimization_b_b3_keeps_query_time_windows() { /// The sliding-window KLL is kept from ingestion time or from query time; not materializing it is the no-window plan. #[test] #[ignore = "needs sliding windows (#522)"] -fn stage2_physical_asap_optimization_b_sliding_kll_has_two_materialization_options() { +fn stage2_physical_asap_optimization_b_sliding_kll_has_two_physical_properties_options() { let found: BTreeSet<_> = options_of( &run_pattern_b_fixture( &pattern_b(), diff --git a/crates/integration-tests/tests/production_rollup_workloads.rs b/crates/integration-tests/tests/production_rollup_workloads.rs index 1c41e2abe..85c4ddd2f 100644 --- a/crates/integration-tests/tests/production_rollup_workloads.rs +++ b/crates/integration-tests/tests/production_rollup_workloads.rs @@ -211,7 +211,7 @@ fn production_promql_compares_rollup_with_exact() { ); } -// Price the same workload with independently built, unmaterialized KLL states. +// Price the same workload with independently built, not_kept KLL states. fn independent_kll_cost( roots: Vec, entries: &[QueryWorkloadEntry], diff --git a/crates/integration-tests/tests/promql_to_post_asap.rs b/crates/integration-tests/tests/promql_to_post_asap.rs index a2e6670d3..ab8c07357 100644 --- a/crates/integration-tests/tests/promql_to_post_asap.rs +++ b/crates/integration-tests/tests/promql_to_post_asap.rs @@ -685,7 +685,7 @@ fn physical_node_owns_phase_independently_of_binary_payload() { use asap_types::ir::properties::ExecutionTiming; // The one-selector case (both operands over the same series, so the // BinaryOp may run at ingestion) is `arithmetic_over_one_selector_executes` - // in materialization_e2e.rs, ignored until #580. + // in physical_properties_e2e.rs, ignored until #580. let query = "sum_over_time(m[1m]) + sum_over_time(n[1m])"; let expected = ExecutionTiming::QueryTime; let input = lower_promql(query, AccuracyTarget::max_error(0.05)).unwrap(); diff --git a/crates/integration-tests/tests/reuse_rules.rs b/crates/integration-tests/tests/reuse_rules.rs index 59865da82..ba041c9ee 100644 --- a/crates/integration-tests/tests/reuse_rules.rs +++ b/crates/integration-tests/tests/reuse_rules.rs @@ -20,8 +20,8 @@ use asap_integration_tests::planning::{ use asap_types::ir::physical_export::compile_physical_asap_dag; use asap_types::ir::properties::AccuracyTarget; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, OperatorNode, QueryRoot, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, OperatorNode, + PhysicalPropertiesAssignment, QueryRoot, }; use asap_types::physical::Lifetime; use asap_types::stages::{root_groups, MemoGroupId}; @@ -112,9 +112,9 @@ fn samples() -> Vec<(&'static str, &'static str, i64, f64)> { /// `Scan`; each `TimeRange` keeps its own window (a tumbling window's moved /// back by the `TimeShift` below it). fn execute(root: &Rc) -> Vec { - let timed = apply_materialization_timings( + let timed = apply_physical_properties( root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); diff --git a/crates/integration-tests/tests/runtime_handoff.rs b/crates/integration-tests/tests/runtime_handoff.rs index 4542413bc..1197a32b8 100644 --- a/crates/integration-tests/tests/runtime_handoff.rs +++ b/crates/integration-tests/tests/runtime_handoff.rs @@ -69,7 +69,7 @@ fn materialized_count(dag: &PhysicalASAPDAG) -> usize { /// export carries that selection rather than resetting every node to /// query time. #[tokio::test] -async fn export_carries_the_selected_materialization() { +async fn export_carries_the_selected_lifetime() { let capabilities = without_raw_data(); let output = plan(&example4b(), &capabilities).await; let dag = output.physical_asap_dag().expect("exports"); diff --git a/crates/integration-tests/tests/tumbling_window_merge.rs b/crates/integration-tests/tests/tumbling_window_merge.rs index 14ba14564..2b8f4feaa 100644 --- a/crates/integration-tests/tests/tumbling_window_merge.rs +++ b/crates/integration-tests/tests/tumbling_window_merge.rs @@ -26,8 +26,8 @@ use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::properties::{AccuracyMetric, AccuracyTarget}; use asap_types::ir::schema::Schema; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, Operator, OperatorNode, QueryRoot, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, + PhysicalPropertiesAssignment, QueryRoot, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use asap_types::test_support::compile_physical_asap_dag_with_node_ids; @@ -177,9 +177,9 @@ struct Exported { builds: Vec<(u64, i64)>, } -fn export(root: &Rc, assignment: &MaterializationAssignment) -> Exported { +fn export(root: &Rc, assignment: &PhysicalPropertiesAssignment) -> Exported { let timed = - apply_materialization_timings(root, assignment, &mut NodeToTimedNodeCache::new()).unwrap(); + apply_physical_properties(root, assignment, &mut NodeToTimedNodeCache::new()).unwrap(); let compiled = compile_physical_asap_dag_with_node_ids(&timed).unwrap(); let tumbling_window = |node: &OperatorNode| -> i64 { match node.children()[0].non_asap() { @@ -259,7 +259,7 @@ fn query_scope() -> Scope { fn compile_at_query_time( root: &Rc, ) -> Result<(Exported, CompiledPhysicalDAG), String> { - let exported = export(root, &MaterializationAssignment::default()); + let exported = export(root, &PhysicalPropertiesAssignment::default()); let plan = compile(&exported.dag, &[], &[exported.dag.roots[0] as u64]).map_err(|e| e.to_string())?; Ok((exported, plan)) @@ -277,7 +277,7 @@ fn execute_retained( tumbling_windows: &[Rc], samples: &[RawDataSample], ) -> Vec> { - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for tumbling_window in tumbling_windows { assignment.set( tumbling_window, @@ -303,7 +303,7 @@ fn execute_maintained_chain( .into_iter() .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. }))) .expect("a tumbling-window chain"); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &chain, PhysicalProperties::new( @@ -313,8 +313,7 @@ fn execute_maintained_chain( .ok(), ); let timed = - apply_materialization_timings(planned, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + apply_physical_properties(planned, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); let expanded = expand_tumbling_window_chains(&timed).unwrap(); for tumbling_window in OperatorNode::reachable(&expanded) .iter() @@ -326,12 +325,12 @@ fn execute_maintained_chain( ); assert_eq!(tumbling_window.timing, Some(ExecutionTiming::IngestionTime)); } - execute_retained_as(&expanded, &MaterializationAssignment::default(), samples) + execute_retained_as(&expanded, &PhysicalPropertiesAssignment::default(), samples) } fn execute_retained_as( root: &Rc, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, samples: &[RawDataSample], ) -> Vec> { let mut exported = export(root, assignment); diff --git a/crates/logical-asap-optimization/src/stage0/cse.rs b/crates/logical-asap-optimization/src/stage0/cse.rs index 5aa44c31a..f8243c9d2 100644 --- a/crates/logical-asap-optimization/src/stage0/cse.rs +++ b/crates/logical-asap-optimization/src/stage0/cse.rs @@ -85,7 +85,7 @@ fn own_fields(node: &OperatorNode) -> Operator<()> { /// hash is SipHash over two parts: /// /// 1. the canonical JSON of [`own_fields`] plus `result_kind`, `schema`, -/// `guarantee`, `timing` and `materialization` — every field `PartialEq` compares except the +/// `guarantee`, `timing` and `lifetime` — every field `PartialEq` compares except the /// children. A scalar expression is serialized as data with each operator /// node it reads replaced by `()`, so a reference to an /// interned sub-DAG contributes nothing of its own here; diff --git a/crates/logical-asap-optimization/src/test_support.rs b/crates/logical-asap-optimization/src/test_support.rs index 1e013975b..356622a69 100644 --- a/crates/logical-asap-optimization/src/test_support.rs +++ b/crates/logical-asap-optimization/src/test_support.rs @@ -109,7 +109,7 @@ use std::time::Duration; use asap_types::ir::operator::agg_intent::AggIntent; use asap_types::ir::operator::operator_properties::{GroupKeys, Reduction, Source}; use asap_types::ir::properties::timing::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{ColumnId, DataType, Field, Schema}; @@ -224,19 +224,19 @@ pub fn time_range(range: Duration, child: Rc) -> Rc /// `root` timed under the default (every sub-DAG not kept) /// assignment — the shape export and the post-ASAP validators consume. pub fn timed(root: &Rc) -> Rc { - apply_materialization_timings( + apply_physical_properties( root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) - .expect("default materialization timings apply") + .expect("default physical properties apply") } /// `root` timed with every sub-DAG kept at ingestion time where the DAG allows it. pub fn at_ingestion(root: &Rc) -> Rc { - apply_materialization_timings( + apply_physical_properties( root, - &MaterializationAssignment::with_default( + &PhysicalPropertiesAssignment::with_default( PhysicalProperties::new( ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory), @@ -245,7 +245,7 @@ pub fn at_ingestion(root: &Rc) -> Rc { ), &mut NodeToTimedNodeCache::new(), ) - .expect("at-ingestion materialization timings apply") + .expect("at-ingestion physical properties apply") } /// The Count-Min summary of a Stage 1 candidate of `query`. diff --git a/crates/physical-asap-optimization/src/catalog/configurations.rs b/crates/physical-asap-optimization/src/catalog/configurations.rs index 6a1f9ae55..956fe25c3 100644 --- a/crates/physical-asap-optimization/src/catalog/configurations.rs +++ b/crates/physical-asap-optimization/src/catalog/configurations.rs @@ -11,8 +11,7 @@ use std::collections::HashMap; use crate::{ kept_across_evaluations_at_ingestion, kept_across_evaluations_at_query_time, - kept_for_one_evaluation, physical_properties as properties, - summary_materialization_eligibility, + kept_for_one_evaluation, physical_properties as properties, summary_keep_eligibility, }; use asap_types::ir::operator::{agg_has_exact_per_entity_kernel, Reduction}; use asap_types::ir::properties::ExecutionTiming; @@ -30,7 +29,7 @@ use asap_types::stages::{ /// [`PhysicalCandidate::may_keep_across_evaluations_per_sole_reader_query`] for `node` configured /// with `properties`: for each query in `entries`, whether -/// `summary_materialization_eligibility` with that query as the only reader +/// `summary_keep_eligibility` with that query as the only reader /// allows keeping it across evaluations. Empty unless `node` is a tumbling-window chain, /// `properties` is query time kept `AcrossEvaluations(Memory)` and the /// deployment keeps query-time results. @@ -49,14 +48,8 @@ pub fn may_keep_across_evaluations_per_sole_reader_query( } (0..entries.len()) .map(|reader| { - summary_materialization_eligibility( - node, - &[reader], - entries, - data, - query_time_results_retained, - ) - .is_ok_and(|eligibility| eligibility.may_keep_across_evaluations) + summary_keep_eligibility(node, &[reader], entries, data, query_time_results_retained) + .is_ok_and(|eligibility| eligibility.may_keep_across_evaluations) }) .collect() } @@ -235,7 +228,7 @@ pub fn enumerate_candidate_configurations( }); if properties == kept_for_one_evaluation() { if !summary { - reader_constraints.push(ReaderConstraint::HighestSharedQueryMaterialization { + reader_constraints.push(ReaderConstraint::HighestSharedOneEvaluation { candidate: id, query_outputs: query_outputs.clone(), }); @@ -387,13 +380,9 @@ fn summary_properties_allowed( data: &DataWorkload, query_time_results_retained: bool, ) -> bool { - let Ok(eligibility) = summary_materialization_eligibility( - node, - readers, - entries, - data, - query_time_results_retained, - ) else { + let Ok(eligibility) = + summary_keep_eligibility(node, readers, entries, data, query_time_results_retained) + else { return false; }; eligibility.range_compatibility.is_ok() diff --git a/crates/physical-asap-optimization/src/catalog/mod.rs b/crates/physical-asap-optimization/src/catalog/mod.rs index cc55d52a9..f4860a090 100644 --- a/crates/physical-asap-optimization/src/catalog/mod.rs +++ b/crates/physical-asap-optimization/src/catalog/mod.rs @@ -27,7 +27,7 @@ pub enum ErrorGeneratingPhysicalASAPMemoCandidates { /// Lowering the memo's candidates to operator nodes failed. #[error(transparent)] Inventory(#[from] CandidateInventoryError), - /// Enumerating timings and materializations failed. + /// Enumerating timings and lifetimes failed. #[error(transparent)] Configuration(#[from] ConfigurationError), /// Structural pruning found the candidates malformed. @@ -36,7 +36,7 @@ pub enum ErrorGeneratingPhysicalASAPMemoCandidates { } /// Stage 2: implement every operator node of every candidate in `logical`'s -/// memo, enumerate the timings and materializations the data and deployment +/// memo, enumerate the timings and lifetimes the data and deployment /// allow (`query_time_results_retained`; no query-time raw scans unless /// `raw_data_retained`; no exact per-entity aggregate the executor cannot /// run), record which candidates may produce each input, and prune what @@ -98,7 +98,7 @@ fn validate_candidates(physical: &PhysicalASAPMemoCandidates) -> Result<(), Stri for constraint in &physical.reader_constraints { let outputs = match constraint { ReaderConstraint::MinimumQueryReaders { query_outputs, .. } - | ReaderConstraint::HighestSharedQueryMaterialization { query_outputs, .. } => { + | ReaderConstraint::HighestSharedOneEvaluation { query_outputs, .. } => { let outputs: Vec<_> = query_outputs.iter().flatten().copied().collect(); let unique: std::collections::HashSet<_> = outputs.iter().copied().collect(); if outputs.len() != outputs_count || unique.len() != outputs.len() { @@ -154,7 +154,7 @@ pub mod test_support { build_candidate_inventory, build_with_compatible_producers_cache, CandidateInventory, }; pub use super::pruning::usable_candidates; - pub use super::realize::{materialize_selected_candidates, restore_query_roots}; + pub use super::realize::{realize_selected_candidates, restore_query_roots}; pub use super::reconstruction::{ ordered_inputs, output_contract_satisfied, paired_node_identities, reconstruct_selected_candidates, ReconstructedCandidates, diff --git a/crates/physical-asap-optimization/src/catalog/realize.rs b/crates/physical-asap-optimization/src/catalog/realize.rs index 4ddab2825..c07bacacb 100644 --- a/crates/physical-asap-optimization/src/catalog/realize.rs +++ b/crates/physical-asap-optimization/src/catalog/realize.rs @@ -1,4 +1,4 @@ -//! Apply an explicit selected materialization assignment through real Stage 2. +//! Apply an explicit selected physical properties assignment through real Stage 2. //! //! No fallback modes are chosen. Physical rewrites or timing splits that change //! candidate identity are rejected until represented by physical enumeration. @@ -21,12 +21,12 @@ use super::reconstruction::{ }; /// Realize `selected` with each selected node at its candidate's -/// materialization. Output +/// physical properties. Output /// references must follow `map_operator_refs` traversal of the original /// roots in workload order (one reference for an operator root). Repeated /// scalar references remain separate positions; literal-only scalar roots /// use none. -pub fn materialize_selected_candidates( +pub fn realize_selected_candidates( physical_candidates: &PhysicalASAPMemoCandidates, selected: &DagOfSelectedCandidates, original_roots: &[QueryRoot], @@ -90,7 +90,7 @@ pub fn materialize_selected_candidates( } let physical = physical.ok_or_else(|| { PhysicalCandidateError::RejectedAssignment( - "selected materialization assignment violates Stage 2 timing or dependency rules" + "selected physical properties assignment violates Stage 2 timing or dependency rules" .into(), ) })?; @@ -103,7 +103,7 @@ pub fn materialize_selected_candidates( // not offer this selected node (e.g. a lower shared non-summary), // so the assignment is infeasible rather than an adapter failure. return Err(PhysicalCandidateError::RejectedAssignment(format!( - "selected node {node} is not an eligible materialization node in the selected graph" + "selected node {node} is not an eligible kept-output node in the selected graph" ))); } } @@ -149,14 +149,14 @@ pub struct Stage2AssignmentRealizer<'a> { } impl AssignmentRealizer for Stage2AssignmentRealizer<'_> { - /// `materialize_selected_candidates`; each node also keeps its + /// `realize_selected_candidates`; each node also keeps its /// candidate's timing. fn realize( &self, physical: &PhysicalASAPMemoCandidates, selected: &DagOfSelectedCandidates, ) -> Result { - let realized = materialize_selected_candidates( + let realized = realize_selected_candidates( physical, selected, self.original_roots, @@ -232,7 +232,7 @@ mod tests { use asap_types::workload::QueryRecurrence; /// Add a node running `candidate` and, for each input, a node of its - /// first unmaterialized producer (else its first producer), + /// first not_kept producer (else its first producer), /// recursively; returns the new node. fn select_from( physical: &PhysicalASAPMemoCandidates, @@ -262,7 +262,7 @@ mod tests { } // The trait object returns what the catalog function returns with each - // candidate's own materialization. + // candidate's own physical properties. #[test] fn stage2_realizer_matches_direct_catalog_calls() { let root = QueryRoot::Operator(lower_promql( @@ -310,7 +310,7 @@ mod tests { let realizer: &dyn AssignmentRealizer = &realizer; let direct = - materialize_selected_candidates(&physical, &selected, &roots, &entries, &data, false) + realize_selected_candidates(&physical, &selected, &roots, &entries, &data, false) .unwrap(); let through_trait = realizer.realize(&physical, &selected).unwrap(); assert_eq!( diff --git a/crates/physical-asap-optimization/src/lib.rs b/crates/physical-asap-optimization/src/lib.rs index a6e7a17ba..c7a713656 100644 --- a/crates/physical-asap-optimization/src/lib.rs +++ b/crates/physical-asap-optimization/src/lib.rs @@ -16,7 +16,7 @@ //! ## Materialization //! //! Each summary build (a `SummaryAgg` or a `SummaryTumblingWindowChain`) is one -//! materialization candidate (`MaterializationCandidate`) whose +//! kept-output candidate (`KeptOutputCandidate`) whose //! output materialization may store (#509 §Materialization, Algorithm 3). //! So is the highest node of each other sub-DAG that two or more queries //! read (e.g. a `Scan` that a 1 m and a 5 m window read): one a root or a @@ -128,8 +128,8 @@ use asap_types::ir::physical_export::compile_physical_asap_workload_with_node_id use asap_types::ir::properties::{ExecutionDataStateError, ExecutionTiming}; use asap_types::ir::schema::{ExactKind, FieldDataType}; use asap_types::ir::{ - apply_materialization_timings, is_filtered_build, ASAPOp, MaterializationAssignment, - NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, ScalarExpr, + apply_physical_properties, is_filtered_build, ASAPOp, NodeToTimedNodeCache, NonASAPOp, + Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, ScalarExpr, SchemaDerivationError, SortKey, }; use asap_types::physical::Medium; @@ -214,7 +214,7 @@ pub(crate) enum IngestionPruneReason { /// These are local options, not a complete physical assignment. Ingestion still /// requires selected upstream implementations to pass timing/down-closure checks. #[derive(Debug)] -pub(crate) struct SummaryMaterializationEligibility { +pub(crate) struct SummaryKeepEligibility { pub(crate) at_ingestion: Result<(), IngestionPruneReason>, pub(crate) may_keep_across_evaluations: bool, /// A tumbling window's selected readers must also meet their range-step grids. @@ -225,9 +225,9 @@ pub(crate) struct SummaryMaterializationEligibility { pub(crate) enum SummaryEligibilityError { #[error("selected reader {query} has no workload entry")] UnknownReader { query: usize }, - #[error("materialization eligibility requires a summary build or tumbling-window chain")] + #[error("keep eligibility requires a summary build or tumbling-window chain")] NotSummary, - #[error("materialization eligibility requires at least one selected reader")] + #[error("keep eligibility requires at least one selected reader")] NoSelectedReaders, #[error("tumbling-window width must be positive")] ZeroPaneWidth, @@ -238,13 +238,13 @@ pub(crate) enum SummaryEligibilityError { /// missing workload entries are rejected as malformed reader references. The node must carry the actual bound source/filter/window subtree, /// and `data` describes that source's arrival. This function does not implement /// operators, assign upstream timing, or prove complete execution legality. -pub(crate) fn summary_materialization_eligibility( +pub(crate) fn summary_keep_eligibility( node: &OperatorNode, selected_readers: &[usize], entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> Result { +) -> Result { if !is_summary_build(node) { return Err(SummaryEligibilityError::NotSummary); } @@ -284,7 +284,7 @@ fn summary_reader_eligibility( entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> SummaryMaterializationEligibility { +) -> SummaryKeepEligibility { let recurrences: Option> = readers .iter() .map(|&query| entries.get(query).map(|entry| &entry.recurrence)) @@ -300,7 +300,7 @@ fn summary_reader_eligibility( ) => builds_one_tumbling_window_per_evaluation(*tumbling_window_width_ms, recurrences), _ => false, }; - SummaryMaterializationEligibility { + SummaryKeepEligibility { at_ingestion: ingestion_eligibility(node, readers, entries, data), may_keep_across_evaluations, range_compatibility: check_summary_range_steps(node, readers, entries), @@ -308,10 +308,10 @@ fn summary_reader_eligibility( } /// One summary build, or one highest shared non-summary node, Stage 2 may -/// store, with its materialization options. +/// store, with its physical properties options. /// It is not a whole-workload plan like [`PhysicalWorkloadPlan`]: it is Stage /// 2's enumeration bookkeeping, and the physical candidates are the -/// combinations of the materialization candidates' options. For example, +/// combinations of the kept-output candidates' options. For example, /// over one metric: /// /// ```text @@ -320,9 +320,9 @@ fn summary_reader_eligibility( /// ``` /// /// If Stage 1 chose KLL tumbling windows for q1 and exact max tumbling windows for q2, Stage 2 -/// finds two materialization candidates: +/// finds two kept-output candidates: /// -/// | materialization candidate | readers | options | +/// | kept-output candidate | readers | options | /// |----------------------------------|---------|---------------------------------| /// | Kll ×5 tumbling windows (q1) | q1 | not kept, kept at ingestion time | /// | Max acc ×5 tumbling windows (q2) | q2 | not kept, kept at ingestion time | @@ -335,9 +335,9 @@ fn summary_reader_eligibility( /// ingestion time over one that is not; Stage 3 prices each. /// `at_ingestion` records why ingestion is ruled out when it is (e.g. /// `Filtered`, `NotRepeated`). Each physical candidate carries the -/// resulting assignment ([`PhysicalWorkloadPlan::materialization`]). +/// resulting assignment ([`PhysicalWorkloadPlan::lifetime`]). #[derive(Debug, Clone)] -pub(crate) struct MaterializationCandidate { +pub(crate) struct KeptOutputCandidate { /// The build in the implemented DAG. pub(crate) node: Rc, /// The queries (indices into the roots) that read it. @@ -350,7 +350,7 @@ pub(crate) struct MaterializationCandidate { pub(crate) may_keep_across_evaluations: bool, } -impl MaterializationCandidate { +impl KeptOutputCandidate { /// Its options, not kept first: kept at ingestion time when eligible, /// `OneEvaluation` when two or more queries read it, and /// query-time `AcrossEvaluations` when it may be kept across @@ -412,7 +412,7 @@ pub(crate) fn builds_one_tumbling_window_per_evaluation<'a>( /// Stage 2 for one CandidateLogicalASAPDAG: implement every operator /// (physical operator implementation), then one physical candidate per -/// materialization assignment of its mat_candidates, the all-not-kept one +/// physical properties assignment of its kept_output_candidates, the all-not-kept one /// first. `entries[i]` is the workload entry of query `i` (`roots[i]`): /// its recurrence and predictability decide whether state may be kept from /// ingestion time; a missing entry is unknown. `id` is left empty for the @@ -431,18 +431,23 @@ pub fn optimize_physical_asap( data: &DataWorkload, query_time_results_retained: bool, ) -> Result, PhysicalASAPOptimizationError> { - let (implemented, _, mat_candidates) = + let (implemented, _, kept_output_candidates) = implement_and_find_candidates(roots, entries, data, query_time_results_retained)?; - materialization_assignments(&mat_candidates) + physical_properties_assignments(&kept_output_candidates) .map(|assignment| { - assigned_candidate(from_logical, &implemented, &mat_candidates, assignment) + assigned_candidate( + from_logical, + &implemented, + &kept_output_candidates, + assignment, + ) }) .collect() } -/// Stage 2 for one CandidateLogicalASAPDAG and one materialization +/// Stage 2 for one CandidateLogicalASAPDAG and one physical properties /// assignment: the physical candidate [`optimize_physical_asap`] lists for -/// it. `choose(readers)` gives the option for each materialization +/// it. `choose(readers)` gives the option for each kept-output /// candidate (each summary build in discovery order, query by query, each /// query's builds as a walk from its root meets them, then each highest /// shared non-summary node in the same order), `readers` being the queries @@ -468,19 +473,19 @@ pub fn optimize_physical_asap_assigned( ) } -/// [`optimize_physical_asap_chosen`]'s choice per materialization +/// [`optimize_physical_asap_chosen`]'s choice per kept-output /// candidate: from the logical node it implements, its readers and its /// options. `None` rejects the assignment. -pub(crate) type ChooseMaterialization<'a> = dyn FnMut( +pub(crate) type ChoosePhysicalProperties<'a> = dyn FnMut( *const OperatorNode, &[usize], &[Option], ) -> Option> + 'a; -/// Stage 2 for one CandidateLogicalASAPDAG and one materialization +/// Stage 2 for one CandidateLogicalASAPDAG and one physical properties /// assignment chosen node by node: `choose(logical, readers, options)` -/// gives the option for each materialization candidate, `logical` being +/// gives the option for each kept-output candidate, `logical` being /// the address of the logical node of `roots` it implements (null when it /// implements none, e.g. a node the implementation adds) and `readers` the /// queries that read it. `None` when `choose` rejects, a chosen option is @@ -493,47 +498,60 @@ pub(crate) fn optimize_physical_asap_chosen( entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, - choose: &mut ChooseMaterialization<'_>, + choose: &mut ChoosePhysicalProperties<'_>, ) -> Result, PhysicalASAPOptimizationError> { - let (implemented, cache, mat_candidates) = + let (implemented, cache, kept_output_candidates) = implement_and_find_candidates(roots, entries, data, query_time_results_retained)?; let logical_of: HashMap<*const OperatorNode, *const OperatorNode> = cache .iter() .map(|(logical, implemented)| (Rc::as_ptr(implemented), *logical)) .collect(); - let mut assignment = Vec::with_capacity(mat_candidates.len()); - for mat_candidate in &mat_candidates { + let mut assignment = Vec::with_capacity(kept_output_candidates.len()); + for kept_output_candidate in &kept_output_candidates { let logical = logical_of - .get(&Rc::as_ptr(&mat_candidate.node)) + .get(&Rc::as_ptr(&kept_output_candidate.node)) .copied() .unwrap_or(std::ptr::null()); - let options = mat_candidate.options(); - let Some(m) = - choose(logical, &mat_candidate.readers, &options).filter(|m| options.contains(m)) + let options = kept_output_candidate.options(); + let Some(m) = choose(logical, &kept_output_candidate.readers, &options) + .filter(|m| options.contains(m)) else { return Ok(None); }; assignment.push(m); } - let nodes: Vec<_> = mat_candidates.iter().map(|c| Rc::clone(&c.node)).collect(); - if !down_closed(&mat_candidates, &candidates_below(&nodes), &assignment) { + let nodes: Vec<_> = kept_output_candidates + .iter() + .map(|c| Rc::clone(&c.node)) + .collect(); + if !down_closed( + &kept_output_candidates, + &candidates_below(&nodes), + &assignment, + ) { return Ok(None); } - assigned_candidate(from_logical, &implemented, &mat_candidates, assignment).map(Some) + assigned_candidate( + from_logical, + &implemented, + &kept_output_candidates, + assignment, + ) + .map(Some) } /// The physical candidate of the implemented roots `implemented` with -/// `assignment[c]` chosen for `mat_candidates[c]`. +/// `assignment[c]` chosen for `kept_output_candidates[c]`. fn assigned_candidate( from_logical: &str, implemented: &[QueryRoot], - mat_candidates: &[MaterializationCandidate], + kept_output_candidates: &[KeptOutputCandidate], assignment: Vec>, ) -> Result { - let mut options = MaterializationAssignment::default(); - for (mat_candidate, kept) in mat_candidates.iter().zip(&assignment) { + let mut options = PhysicalPropertiesAssignment::default(); + for (kept_output_candidate, kept) in kept_output_candidates.iter().zip(&assignment) { if kept.is_some() { - options.set(&mat_candidate.node, *kept); + options.set(&kept_output_candidate.node, *kept); } } let operators: Vec> = implemented @@ -551,7 +569,7 @@ fn assigned_candidate( })?; let mut timing = NodeToTimedNodeCache::new(); let timed = map_roots(&split_roots, &mut |node| { - Ok(apply_materialization_timings(node, &options, &mut timing)?) + Ok(apply_physical_properties(node, &options, &mut timing)?) })?; let dag = compile_physical_asap_workload_with_node_ids(&timed)?.dag; let lifetime = dag @@ -577,7 +595,7 @@ fn assigned_candidate( } /// `roots` implemented, the implementation of each logical node, and the -/// materialization candidates of the implemented roots. +/// kept-output candidates of the implemented roots. fn implement_and_find_candidates( roots: &[QueryRoot], entries: &[QueryWorkloadEntry], @@ -587,16 +605,16 @@ fn implement_and_find_candidates( ( Vec, NodeToImplementedNodeCache, - Vec, + Vec, ), PhysicalASAPOptimizationError, > { let mut cache = HashMap::new(); let implemented = map_roots(roots, &mut |node| implement(node, &mut cache))?; - let mat_candidates = - materialization_candidates(&implemented, entries, data, query_time_results_retained); - check_tumbling_windows_on_range_steps(&mat_candidates, entries)?; - Ok((implemented, cache, mat_candidates)) + let kept_output_candidates = + find_kept_output_candidates(&implemented, entries, data, query_time_results_retained); + check_tumbling_windows_on_range_steps(&kept_output_candidates, entries)?; + Ok((implemented, cache, kept_output_candidates)) } /// `Err` for the first tumbling-window chain whose tumbling-window width does not @@ -604,10 +622,10 @@ fn implement_and_find_candidates( /// ([`PhysicalASAPOptimizationError::TumblingWindowWidthOffRangeStep`]): that step /// would end inside a tumbling window. fn check_tumbling_windows_on_range_steps( - mat_candidates: &[MaterializationCandidate], + kept_output_candidates: &[KeptOutputCandidate], entries: &[QueryWorkloadEntry], ) -> Result<(), PhysicalASAPOptimizationError> { - for candidate in mat_candidates { + for candidate in kept_output_candidates { check_summary_range_steps(&candidate.node, &candidate.readers, entries)?; } Ok(()) @@ -653,7 +671,7 @@ fn is_summary_build(node: &OperatorNode) -> bool { ) } -/// The materialization candidates of `roots` (implemented), with their +/// The kept-output candidates of `roots` (implemented), with their /// readers, whether each may run at ingestion time and whether it may be /// kept from query time across evaluations: every summary build, in /// discovery order, then every highest shared non-summary node, in @@ -661,12 +679,12 @@ fn is_summary_build(node: &OperatorNode) -> bool { /// highest are those a root or an unshared node reads (e.g. a `Scan` that /// two windows read). Only a highest one is offered `OneEvaluation`, so a /// shared sub-DAG adds one candidate, not one per node. -pub(crate) fn materialization_candidates( +pub(crate) fn find_kept_output_candidates( roots: &[QueryRoot], entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> Vec { +) -> Vec { let mut reached: Vec> = Vec::new(); let mut readers: HashMap<*const OperatorNode, Vec> = HashMap::new(); let mut consumers: HashMap<*const OperatorNode, Vec<*const OperatorNode>> = HashMap::new(); @@ -709,15 +727,15 @@ pub(crate) fn materialization_candidates( summary_reader_eligibility(node, &readers, entries, data, query_time_results_retained); let at_ingestion = eligibility.at_ingestion.and_then(|()| { // Only this build and the builds below it at ingestion time. - let mut trial = MaterializationAssignment::default(); + let mut trial = PhysicalPropertiesAssignment::default(); for &v in below[c].iter().chain([&c]) { trial.set(&nodes[v], Some(kept_across_evaluations_at_ingestion())); } - apply_materialization_timings(node, &trial, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(node, &trial, &mut NodeToTimedNodeCache::new()) .map(|_| ()) .map_err(|e| IngestionPruneReason::UpstreamAtQueryTime(e.to_string())) }); - MaterializationCandidate { + KeptOutputCandidate { node: Rc::clone(node), readers, at_ingestion, @@ -728,7 +746,7 @@ pub(crate) fn materialization_candidates( let shared_results = shared_results .into_iter() .filter(|n| highest_shared(n) && n.timing != Some(ExecutionTiming::IngestionTime)) - .map(|node| MaterializationCandidate { + .map(|node| KeptOutputCandidate { readers: readers[&Rc::as_ptr(&node)].clone(), node, at_ingestion: Err(IngestionPruneReason::NotASummaryBuild), @@ -807,7 +825,7 @@ fn ingestion_eligibility( tumbling_window_width_ms, .. }) => (family, Some(*tumbling_window_width_ms)), - _ => unreachable!("a materialization candidate is a summary build"), + _ => unreachable!("a kept-output candidate is a summary build"), }; if matches!( family, @@ -944,9 +962,9 @@ fn candidates_below(nodes: &[Rc]) -> Vec> { /// query-time readers read a copy ([`split_shared_by_timing`]). /// Simplification: that copy is not offered `OneEvaluation` even when two /// query-time readers remain. `below` is [`candidates_below`] of -/// `mat_candidates`. +/// `kept_output_candidates`. fn down_closed( - mat_candidates: &[MaterializationCandidate], + kept_output_candidates: &[KeptOutputCandidate], below: &[Vec], assignment: &[Option], ) -> bool { @@ -956,7 +974,7 @@ fn down_closed( assignment.iter().enumerate().all(|(c, m)| { !at_ingestion(m) || below[c].iter().all(|&v| { - if is_summary_build(&mat_candidates[v].node) { + if is_summary_build(&kept_output_candidates[v].node) { at_ingestion(&assignment[v]) } else { assignment[v].is_none() @@ -965,18 +983,21 @@ fn down_closed( }) } -/// Every assignment of an option to each materialization candidate (mixed +/// Every assignment of an option to each kept-output candidate (mixed /// radix, the last varying fastest, all not kept first) that is /// [`down_closed`]. #[cfg(any(test, feature = "reference-pricer"))] -fn materialization_assignments( - mat_candidates: &[MaterializationCandidate], +fn physical_properties_assignments( + kept_output_candidates: &[KeptOutputCandidate], ) -> impl Iterator>> + '_ { let options: Vec>> = - mat_candidates.iter().map(|c| c.options()).collect(); - let nodes: Vec<_> = mat_candidates.iter().map(|c| Rc::clone(&c.node)).collect(); + kept_output_candidates.iter().map(|c| c.options()).collect(); + let nodes: Vec<_> = kept_output_candidates + .iter() + .map(|c| Rc::clone(&c.node)) + .collect(); let below = candidates_below(&nodes); - let mut digits = Some(vec![0usize; mat_candidates.len()]); + let mut digits = Some(vec![0usize; kept_output_candidates.len()]); std::iter::from_fn(move || loop { let current = digits.as_mut()?; let assignment: Vec> = current @@ -997,7 +1018,7 @@ fn materialization_assignments( if carried { digits = None; } - if down_closed(mat_candidates, &below, &assignment) { + if down_closed(kept_output_candidates, &below, &assignment) { return Some(assignment); } digits.as_ref()?; @@ -1182,7 +1203,7 @@ pub mod test_support { entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, - choose: &mut crate::ChooseMaterialization<'_>, + choose: &mut crate::ChoosePhysicalProperties<'_>, ) -> Result, PhysicalASAPOptimizationError> { crate::optimize_physical_asap_chosen( from_logical, @@ -1637,34 +1658,24 @@ mod tests { ]; let data = arriving(); let query_time_results_retained = false; - let selected = summary_materialization_eligibility( - &node, - &[0, 0], - &entries, - &data, - query_time_results_retained, - ) - .unwrap(); + let selected = + summary_keep_eligibility(&node, &[0, 0], &entries, &data, query_time_results_retained) + .unwrap(); assert_eq!(selected.at_ingestion, Ok(())); assert!(matches!( - summary_materialization_eligibility(&node, &[0, entries.len()], &entries, &data, query_time_results_retained), + summary_keep_eligibility(&node, &[0, entries.len()], &entries, &data, query_time_results_retained), Err(SummaryEligibilityError::UnknownReader { query }) if query == entries.len() )); - let combined = summary_materialization_eligibility( - &node, - &[0, 1], - &entries, - &data, - query_time_results_retained, - ) - .unwrap(); + let combined = + summary_keep_eligibility(&node, &[0, 1], &entries, &data, query_time_results_retained) + .unwrap(); assert_eq!( combined.at_ingestion, Err(IngestionPruneReason::NotPredictable) ); // The complete-DAG path uses the same selected-reader workload rules. let candidates = - materialization_candidates(&[root], &entries, &data, query_time_results_retained); + find_kept_output_candidates(&[root], &entries, &data, query_time_results_retained); let original = candidates .iter() .find(|candidate| { @@ -1712,49 +1723,28 @@ mod tests { ]; let query_time_results_retained = true; let data = arriving(); - let one = summary_materialization_eligibility( - &node, - &[0], - &entries, - &data, - query_time_results_retained, - ) - .unwrap(); + let one = + summary_keep_eligibility(&node, &[0], &entries, &data, query_time_results_retained) + .unwrap(); assert!(one.may_keep_across_evaluations); assert!(one.range_compatibility.is_ok()); - let different_phase = summary_materialization_eligibility( - &node, - &[0, 1], - &entries, - &data, - query_time_results_retained, - ) - .unwrap(); + let different_phase = + summary_keep_eligibility(&node, &[0, 1], &entries, &data, query_time_results_retained) + .unwrap(); assert!(!different_phase.may_keep_across_evaluations); assert_eq!( different_phase.at_ingestion, Err(IngestionPruneReason::TumblingWindowsOffPhase) ); - let off_grid = summary_materialization_eligibility( - &node, - &[0, 2], - &entries, - &data, - query_time_results_retained, - ) - .unwrap(); + let off_grid = + summary_keep_eligibility(&node, &[0, 2], &entries, &data, query_time_results_retained) + .unwrap(); assert!(matches!( off_grid.range_compatibility, Err(PhysicalASAPOptimizationError::TumblingWindowWidthOffRangeStep { .. }) )); assert!(matches!( - summary_materialization_eligibility( - &node, - &[], - &entries, - &data, - query_time_results_retained - ), + summary_keep_eligibility(&node, &[], &entries, &data, query_time_results_retained), Err(SummaryEligibilityError::NoSelectedReaders) )); } @@ -1851,7 +1841,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - materialization_candidates(&implemented, &demands, &arriving(), false) + find_kept_output_candidates(&implemented, &demands, &arriving(), false) .into_iter() .find(|c| { matches!( @@ -1859,7 +1849,7 @@ mod tests { Some(ASAPOp::SummaryTumblingWindowChain { .. }) ) }) - .expect("the chain is a materialization candidate") + .expect("the chain is a kept-output candidate") .at_ingestion }; assert_eq!(at_ingestion([at(0), at(2 * MINUTE)]), Ok(())); @@ -1902,7 +1892,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - materialization_candidates(&implemented, &demands, &arriving(), false) + find_kept_output_candidates(&implemented, &demands, &arriving(), false) .into_iter() .find(|c| { matches!( @@ -1910,7 +1900,7 @@ mod tests { Some(ASAPOp::SummaryTumblingWindowChain { .. }) ) }) - .expect("the chain is a materialization candidate") + .expect("the chain is a kept-output candidate") .at_ingestion }; assert_eq!(at_ingestion([every_minute(), every(2 * MINUTE)]), Ok(())); @@ -1926,7 +1916,7 @@ mod tests { /// S4: maintaining state at ingestion time needs arriving data and /// queries that repeat and are predictable; otherwise the chain only - /// runs at query time, and the materialization candidate says why. + /// runs at query time, and the kept-output candidate says why. #[test] fn ingestion_time_needs_arriving_data_and_repeated_predictable_queries() { use IngestionPruneReason as Why; @@ -1959,9 +1949,10 @@ mod tests { assert_eq!(candidates.len(), 1, "{why:?}"); let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let mat_candidates = materialization_candidates(&implemented, &[demand], &data, false); - assert_eq!(mat_candidates.len(), 1); - assert_eq!(mat_candidates[0].at_ingestion, Err(why)); + let kept_output_candidates = + find_kept_output_candidates(&implemented, &[demand], &data, false); + assert_eq!(kept_output_candidates.len(), 1); + assert_eq!(kept_output_candidates[0].at_ingestion, Err(why)); } } @@ -1975,9 +1966,9 @@ mod tests { let roots = [in_tumbling_windows(summary_root(query))]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let mat_candidates = - materialization_candidates(&implemented, &[every_minute()], &arriving(), false); - assert_eq!(mat_candidates[0].at_ingestion, Ok(()), "{query}"); + let kept_output_candidates = + find_kept_output_candidates(&implemented, &[every_minute()], &arriving(), false); + assert_eq!(kept_output_candidates[0].at_ingestion, Ok(()), "{query}"); let candidates = optimize_physical_asap("L1", &roots, &[every_minute()], &arriving(), false) .unwrap(); @@ -2006,10 +1997,10 @@ mod tests { let roots = [root]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let mat_candidates = - materialization_candidates(&implemented, &[every_minute()], &data, false); + let kept_output_candidates = + find_kept_output_candidates(&implemented, &[every_minute()], &data, false); assert_eq!( - mat_candidates[0].at_ingestion, + kept_output_candidates[0].at_ingestion, Err(Why::CounterNeedsTimeOrder) ); } @@ -2050,60 +2041,60 @@ mod tests { ..every_minute() }; let at = |interval_ms: u32| at_phase(interval_ms, 0); - let mat_candidates = |root: &QueryRoot, demand: QueryWorkloadEntry| { + let kept_output_candidates = |root: &QueryRoot, demand: QueryWorkloadEntry| { let mut cache = HashMap::new(); let implemented = map_roots(std::slice::from_ref(root), &mut |n| { implement(n, &mut cache) }) .unwrap(); - materialization_candidates(&implemented, &[demand], &arriving(), false) + find_kept_output_candidates(&implemented, &[demand], &arriving(), false) .remove(0) .at_ingestion }; - assert_eq!(mat_candidates(&root, at(MINUTE as u32)), Ok(())); - assert_eq!(mat_candidates(&root, every_minute()), Ok(())); - assert_eq!(mat_candidates(&root, at(2 * MINUTE as u32)), Ok(())); + assert_eq!(kept_output_candidates(&root, at(MINUTE as u32)), Ok(())); + assert_eq!(kept_output_candidates(&root, every_minute()), Ok(())); + assert_eq!(kept_output_candidates(&root, at(2 * MINUTE as u32)), Ok(())); assert_eq!( - mat_candidates(&root, at_phase(MINUTE as u32, 3 * MINUTE)), + kept_output_candidates(&root, at_phase(MINUTE as u32, 3 * MINUTE)), Ok(()) ); assert_eq!( - mat_candidates(&root, at_phase(MINUTE as u32, 30_000)), + kept_output_candidates(&root, at_phase(MINUTE as u32, 30_000)), Err(Why::WindowOffEpochGrid) ); assert_eq!( - mat_candidates(&root, at(30_000)), + kept_output_candidates(&root, at(30_000)), Err(Why::WindowOffEpochGrid) ); assert_eq!( - mat_candidates(&root, at(90_000)), + kept_output_candidates(&root, at(90_000)), Err(Why::WindowOffEpochGrid) ); // Several readers of one build: a declared phase on the grid and an // undeclared one agree; two declared phases, or two intervals, do not. - let mat_candidates_of = |demands: &[QueryWorkloadEntry]| { + let kept_output_candidates_of = |demands: &[QueryWorkloadEntry]| { let roots = vec![root.clone(); demands.len()]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - materialization_candidates(&implemented, demands, &arriving(), false) + find_kept_output_candidates(&implemented, demands, &arriving(), false) .into_iter() .find(|c| matches!(c.node.asap(), Some(ASAPOp::SummaryAgg { .. }))) - .expect("the whole-window build is a materialization candidate") + .expect("the whole-window build is a kept-output candidate") .at_ingestion }; assert_eq!( - mat_candidates_of(&[at_phase(MINUTE as u32, MINUTE), every_minute()]), + kept_output_candidates_of(&[at_phase(MINUTE as u32, MINUTE), every_minute()]), Ok(()) ); assert_eq!( - mat_candidates_of(&[ + kept_output_candidates_of(&[ at(MINUTE as u32), at_phase(MINUTE as u32, 2 * MINUTE + MINUTE / 2) ]), Err(Why::WindowNotFixed) ); assert_eq!( - mat_candidates_of(&[at(MINUTE as u32), at(2 * MINUTE as u32)]), + kept_output_candidates_of(&[at(MINUTE as u32), at(2 * MINUTE as u32)]), Err(Why::WindowNotFixed) ); let candidates = optimize_physical_asap( @@ -2152,7 +2143,7 @@ mod tests { .with_guarantee(build.guarantee.clone()), ); assert_eq!( - mat_candidates(&QueryRoot::Operator(filtered), at(MINUTE as u32)), + kept_output_candidates(&QueryRoot::Operator(filtered), at(MINUTE as u32)), Err(Why::Filtered) ); } @@ -2182,7 +2173,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - materialization_candidates(&implemented, &[entry], &arriving(), false) + find_kept_output_candidates(&implemented, &[entry], &arriving(), false) .remove(0) .at_ingestion }; @@ -2331,10 +2322,10 @@ mod tests { scans.sort_by_key(|(t, _)| *t == ExecutionTiming::QueryTime); scans }; - let not_materialized = Lifetime::None; + let not_kept = Lifetime::None; assert_eq!( scans(&candidates[0]), - [(ExecutionTiming::QueryTime, not_materialized)] + [(ExecutionTiming::QueryTime, not_kept)] ); assert_eq!( scans(&candidates[1]), @@ -2346,13 +2337,13 @@ mod tests { assert_eq!( scans(&candidates[2]), [ - (ExecutionTiming::IngestionTime, not_materialized), - (ExecutionTiming::QueryTime, not_materialized) + (ExecutionTiming::IngestionTime, not_kept), + (ExecutionTiming::QueryTime, not_kept) ] ); } - /// Only the highest shared non-summary nodes are materialization + /// Only the highest shared non-summary nodes are kept-output /// candidates, each with not kept and `OneEvaluation` only: a /// 5 m range two queries read (not the scan below it, which only that /// shared range reads for them), and the scan, which a third query @@ -2389,9 +2380,9 @@ mod tests { aggregate(AggIntent::Min { col: None }, five_minutes), aggregate(AggIntent::Max { col: None }, ranged(MINUTE)), ]; - let mat_candidates = - materialization_candidates(&roots, &[], &DataWorkload::default(), false); - let found: Vec<_> = mat_candidates + let kept_output_candidates = + find_kept_output_candidates(&roots, &[], &DataWorkload::default(), false); + let found: Vec<_> = kept_output_candidates .iter() .map(|c| (c.node.operator.kind_name(), c.readers.clone(), c.options())) .collect(); diff --git a/crates/physical-asap-optimization/src/split_by_timing.rs b/crates/physical-asap-optimization/src/split_by_timing.rs index 9a71eb28d..23f8fb09f 100644 --- a/crates/physical-asap-optimization/src/split_by_timing.rs +++ b/crates/physical-asap-optimization/src/split_by_timing.rs @@ -1,11 +1,11 @@ //! Splitting a shared sub-DAG by execution timing before Stage 2 applies a -//! materialization assignment ([`split_shared_by_timing`]). +//! physical properties assignment ([`split_shared_by_timing`]). use std::collections::HashMap; use std::rc::Rc; use asap_types::ir::properties::ExecutionTiming; -use asap_types::ir::{timing_under_consumer, MaterializationAssignment, OperatorNode}; +use asap_types::ir::{timing_under_consumer, OperatorNode, PhysicalPropertiesAssignment}; /// Each (node, timing) pair's rebuilt node, with the original it copies. type Copies = HashMap<(*const OperatorNode, ExecutionTiming), (Rc, Rc)>; @@ -21,15 +21,15 @@ type Copies = HashMap<(*const OperatorNode, ExecutionTiming), (Rc, /// keeps its original's explicit materialization. pub fn split_shared_by_timing( roots: &[Rc], - assignment: &MaterializationAssignment, -) -> (Vec>, MaterializationAssignment) { + assignment: &PhysicalPropertiesAssignment, +) -> (Vec>, PhysicalPropertiesAssignment) { // First pass: the set of timings each node is reached with. let mut reached: HashMap<*const OperatorNode, Vec> = HashMap::new(); let mut forced = HashMap::new(); fn collect( node: &Rc, consumer: ExecutionTiming, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, reached: &mut HashMap<*const OperatorNode, Vec>, forced: &mut HashMap<*const OperatorNode, bool>, ) { @@ -61,7 +61,7 @@ pub fn split_shared_by_timing( fn rebuild( node: &Rc, consumer: ExecutionTiming, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, reached: &HashMap<*const OperatorNode, Vec>, copies: &mut Copies, forced: &mut HashMap<*const OperatorNode, bool>, @@ -128,7 +128,7 @@ mod tests { }; use asap_types::ir::schema::{DataType, Field, FieldDataType, Schema}; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; @@ -245,9 +245,9 @@ mod tests { })) .unwrap(); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &root, - &MaterializationAssignment::with_default(at_ingestion()), + &PhysicalPropertiesAssignment::with_default(at_ingestion()), &mut NodeToTimedNodeCache::new() ) .err(), @@ -258,9 +258,9 @@ mod tests { ); let (split, assignment) = split_shared_by_timing( std::slice::from_ref(&root), - &MaterializationAssignment::with_default(at_ingestion()), + &PhysicalPropertiesAssignment::with_default(at_ingestion()), ); - assert!(apply_materialization_timings( + assert!(apply_physical_properties( &split[0], &assignment, &mut NodeToTimedNodeCache::new() @@ -278,11 +278,11 @@ mod tests { children: vec![max(estimate(Rc::clone(&summary))), max(Rc::clone(&shared))], })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&summary, at_ingestion()); let (split, assignment) = split_shared_by_timing(std::slice::from_ref(&root), &assignment); let timed = - apply_materialization_timings(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let summary = child(&child(&child(&timed))); assert!(matches!( @@ -309,13 +309,13 @@ mod tests { concat(vec![Rc::clone(&by_summary), Rc::clone(&common)]), concat(vec![raw, Rc::clone(&common)]), ]; - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&summary, at_ingestion()); let timed_unsplit = { let mut cache = NodeToTimedNodeCache::new(); roots .iter() - .map(|root| apply_materialization_timings(root, &assignment, &mut cache)) + .map(|root| apply_physical_properties(root, &assignment, &mut cache)) .collect::, _>>() }; assert!(matches!( @@ -327,7 +327,7 @@ mod tests { let mut cache = NodeToTimedNodeCache::new(); let timed: Vec<_> = split .iter() - .map(|root| apply_materialization_timings(root, &assignment, &mut cache).unwrap()) + .map(|root| apply_physical_properties(root, &assignment, &mut cache).unwrap()) .collect(); let summary = child(&child(&child(&timed[0]))); assert_eq!(summary.lifetime, KEPT_ACROSS); @@ -356,7 +356,7 @@ mod tests { .clone() .with_timing(Some(ExecutionTiming::QueryTime)), ); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&summary, at_ingestion()); assignment.set(&state, at_ingestion()); assignment.set(&read, at_ingestion()); @@ -364,12 +364,12 @@ mod tests { let mut cache = NodeToTimedNodeCache::new(); let timed: Result, _> = split .iter() - .map(|root| apply_materialization_timings(root, &assignment, &mut cache)) + .map(|root| apply_physical_properties(root, &assignment, &mut cache)) .collect(); assert_eq!( timed.err(), Some( - ExecutionDataStateError::MaterializationConflictsWithFixedTiming { + ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, assigned: at_ingestion().unwrap(), diff --git a/crates/plan-selection/src/groups.rs b/crates/plan-selection/src/groups.rs index 6c917282e..565b32ee9 100644 --- a/crates/plan-selection/src/groups.rs +++ b/crates/plan-selection/src/groups.rs @@ -1,6 +1,6 @@ //! #1095 C3: what the owner-scoped candidate MILP (§2.0) is built from. Given //! Stage 2's physical candidates (one per operator node, timing and -//! materialization; Stage 2 makes no copies), it computes: +//! lifetime; Stage 2 makes no copies), it computes: //! //! 1. **Candidate dominance** ([`prune_dominated_candidates`]): a candidate no optimal //! plan under cost model 1 uses is deleted, with its links. diff --git a/crates/plan-selection/src/groups/accuracy_positions.rs b/crates/plan-selection/src/groups/accuracy_positions.rs index ec1f840a7..3c1688c1b 100644 --- a/crates/plan-selection/src/groups/accuracy_positions.rs +++ b/crates/plan-selection/src/groups/accuracy_positions.rs @@ -16,7 +16,7 @@ //! `S` is usable for `q` only when every output passes: a candidate that //! fails through one reader is unusable through every reader (the largest //! weight counts, as before). The candidates of one operator node (other -//! timings or materializations) build the same node, so they are checked +//! timings or lifetimes) build the same node, so they are checked //! once, together. What a check builds is kept for the later checks //! ([`BuiltBefore`]). use std::cell::OnceCell; diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index 04e3af388..e641a8b72 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -1120,7 +1120,7 @@ mod tests { /// twice. Materializing query 2's root (`OneEvaluation`) charges it once, /// and the nodes below it once, since they run only when it does. #[test] - fn not_materialized_shared_nodes_are_charged_per_query() { + fn not_kept_shared_nodes_are_charged_per_query() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let mut candidate = optimize_physical_asap( @@ -1177,7 +1177,7 @@ mod tests { /// latency at both rates. Query 1 is `sum(...)` over query 2's output, /// so it runs longer; they repeat every 10 s and every 20 s. #[test] - fn shared_not_materialized_memory_is_held_for_each_reading_query() { + fn shared_not_kept_memory_is_held_for_each_reading_query() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let candidate = optimize_physical_asap( @@ -2818,7 +2818,7 @@ mod tests { } /// Every whole plan of `roots`: each combination of Pass 1's choices - /// composed, then every materialization assignment Stage 2 offers for + /// composed, then every physical properties assignment Stage 2 offers for /// it, with unique ids. fn exhaustive_candidates( roots: &[QueryRoot], @@ -3423,7 +3423,7 @@ mod tests { /// state kept with `kept` (`None`: not kept). fn kll_dag(kept: Option) -> PhysicalASAPDAG { use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; let root = lower_promql( "quantile_over_time(0.99, m[1m])", @@ -3461,11 +3461,10 @@ mod tests { .into_iter() .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryAgg { .. }))) .expect("a KLL state"); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&state, kept); let timed = - apply_materialization_timings(root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); asap_types::ir::physical_export::compile_physical_asap_workload_with_node_ids(&[ QueryRoot::Operator(timed), ]) @@ -3614,8 +3613,8 @@ mod tests { let settings = unit_costs(|c| c.cost_per_memory_byte_second = w); price(dag, &recurrences(1), &data(), &settings).unwrap() }; - for materialization in [at_ingestion(), at_query(), None] { - let dag = kll_dag(materialization); + for kept in [at_ingestion(), at_query(), None] { + let dag = kll_dag(kept); let build = node_of(&dag, is_build); let (with, without) = (cost(&dag, 1.25e-7), cost(&dag, 0.0)); let Payload::ASAP(ASAPOp::SummaryAgg { family, .. }) = @@ -3627,7 +3626,7 @@ mod tests { // each sees its series' 12 samples: the 120 000 rows of its // source's 1-min window (data()'s 10 000 rows per second over its // five sources); at ingestion time its samples are unknown. - let samples = if materialization == at_ingestion() { + let samples = if kept == at_ingestion() { StateInputRows::UNKNOWN } else { StateInputRows { @@ -3636,7 +3635,7 @@ mod tests { } }; let state = 10_000.0 * summary_shape(family, samples).1 as f64; - let byte_seconds = if materialization == at_ingestion() { + let byte_seconds = if kept == at_ingestion() { 2.0 * state } else { let evaluation_s = with.usage.latency_per_query[0].total_ms() / 1_000.0; @@ -3649,7 +3648,7 @@ mod tests { - without.per_node[&build].cost_per_second.unwrap(); assert!( close(term, 1.25e-7 * byte_seconds), - "{materialization:?}: {term} vs {}", + "{kept:?}: {term} vs {}", 1.25e-7 * byte_seconds ); // The candidate's memory term covers every node's held memory, @@ -3695,8 +3694,8 @@ mod tests { (query.to_string(), dag) }) .collect(); - for materialization in [at_ingestion(), at_query(), None] { - dags.push((format!("{materialization:?}"), kll_dag(materialization))); + for kept in [at_ingestion(), at_query(), None] { + dags.push((format!("{kept:?}"), kll_dag(kept))); } for (name, dag) in &dags { let (term, usage) = memory_term(dag); diff --git a/crates/plan-selection/src/milp/model.rs b/crates/plan-selection/src/milp/model.rs index ffd268768..65ada5529 100644 --- a/crates/plan-selection/src/milp/model.rs +++ b/crates/plan-selection/src/milp/model.rs @@ -1178,7 +1178,7 @@ fn shareables_needing_exact_reach(milp: &SelectionMilp<'_>) -> BTreeSet) { .row("9 reader constraints", constraint!(count >= minimum * used)); } } - ReaderConstraint::HighestSharedQueryMaterialization { query_outputs, .. } => { + ReaderConstraint::HighestSharedOneEvaluation { query_outputs, .. } => { let queries = bucket_queries(&query_of_reference, query_outputs); if shareable { let Some(&selected) = milp.selected.get(&candidate) else { @@ -1343,7 +1343,7 @@ fn reader_constraint_rows(milp: &mut SelectionMilp<'_>) { } ContextKind::Ingestion(_) => { milp.note_inexact( - "highest shared materialization in an I_r (forbidden)", + "highest shared OneEvaluation result in an I_r (forbidden)", ); milp.builder .row("9 reader constraints", constraint!(used <= 0.0)); diff --git a/crates/plan-selection/src/milp/model/tests.rs b/crates/plan-selection/src/milp/model/tests.rs index f6bb31384..9e9558de6 100644 --- a/crates/plan-selection/src/milp/model/tests.rs +++ b/crates/plan-selection/src/milp/model/tests.rs @@ -498,7 +498,7 @@ fn a_kept_pane_chain_keeps_the_longest_readers_span() { // (`rate(m[5m])` under `sum` and `max`, one schedule group) runs once, in // the candidate's context, and is costed as `plan_cost` costs it. #[test] -fn a_shared_results_not_materialized_input_runs_once() { +fn a_shared_results_not_kept_input_runs_once() { let fixture = through_stages( &[ query("sum(rate(m[5m]))", 60_000), diff --git a/crates/plan-selection/src/milp/warm_start.rs b/crates/plan-selection/src/milp/warm_start.rs index b7de6ae37..cf2da1520 100644 --- a/crates/plan-selection/src/milp/warm_start.rs +++ b/crates/plan-selection/src/milp/warm_start.rs @@ -459,7 +459,7 @@ impl Derivation<'_, '_> { left, right, } => *c == candidate && references.contains(left) && references.contains(right), - ReaderConstraint::HighestSharedQueryMaterialization { .. } => false, + ReaderConstraint::HighestSharedOneEvaluation { .. } => false, }) } diff --git a/crates/planner/src/installable.rs b/crates/planner/src/installable.rs index 86592d37f..317425809 100644 --- a/crates/planner/src/installable.rs +++ b/crates/planner/src/installable.rs @@ -40,7 +40,7 @@ use asap_types::ir::physical_export::{ use asap_types::ir::properties::{ExecutionDataStateError, ExecutionTiming}; use asap_types::ir::SchemaDerivationError; use asap_types::ir::{ - apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, OperatorNode, + apply_physical_properties_to_roots, ASAPOp, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, }; use asap_types::workload::QueryWorkloadEntry; @@ -282,7 +282,7 @@ pub fn installable_plan_of( let query_texts: Vec = entries.iter().map(|entry| entry.query.0.clone()).collect(); // Every node keeps the timing Stage 3 gave it. let timed = - apply_materialization_timings_to_roots(roots, &MaterializationAssignment::default())?; + apply_physical_properties_to_roots(roots, &PhysicalPropertiesAssignment::default())?; let expanded = tumbling_window_retention_of_expanded_tumbling_windows( &timed, tumbling_window_retention_ms, @@ -871,7 +871,7 @@ mod tests { use asap_types::ir::physical_export::compile_physical_asap_dag; use asap_types::ir::schema::{DataType, Field, Schema}; use asap_types::ir::{ - apply_materialization_timings, NodeToTimedNodeCache, OperatorNode, TimeRangeKind, + apply_physical_properties, NodeToTimedNodeCache, OperatorNode, TimeRangeKind, }; use std::time::Duration; let scan = OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { @@ -904,9 +904,9 @@ mod tests { })) .unwrap(); let export = |root| { - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -949,7 +949,7 @@ mod tests { DataType, ExactKind, ExactParams, Field, FieldDataType, Schema, SummaryUpdate, }; use asap_types::ir::{ - apply_materialization_timings, NodeToTimedNodeCache, OperatorNode, TimeRangeKind, + apply_physical_properties, NodeToTimedNodeCache, OperatorNode, TimeRangeKind, }; use asap_types::physical::Medium; use std::time::Duration; @@ -999,7 +999,7 @@ mod tests { filter: None, })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &merged, PhysicalProperties::new( @@ -1009,7 +1009,7 @@ mod tests { .ok(), ); let timed = - apply_materialization_timings(&merged, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&merged, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let dag = compile_physical_asap_dag(&timed).unwrap(); match InstallablePlan::of_dag(dag, vec![String::new()], &HashMap::new(), &HashMap::new()) { @@ -1042,7 +1042,7 @@ mod tests { group_by: None, })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for node in tumbling_windows.iter().chain([&merge]) { assignment.set( node, @@ -1054,7 +1054,7 @@ mod tests { ); } let timed = - apply_materialization_timings(&merge, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&merge, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let dag = compile_physical_asap_dag(&timed).unwrap(); match InstallablePlan::of_dag(dag, vec![String::new()], &HashMap::new(), &HashMap::new()) { diff --git a/crates/planner/src/pass.rs b/crates/planner/src/pass.rs index 5ded2a5a8..91fcce57b 100644 --- a/crates/planner/src/pass.rs +++ b/crates/planner/src/pass.rs @@ -18,7 +18,7 @@ use std::rc::Rc; use asap_types::ir::physical_export::compile_physical_asap_workload; use asap_types::ir::properties::timing::{ - apply_materialization_timings_to_roots, MaterializationAssignment, + apply_physical_properties_to_roots, PhysicalPropertiesAssignment, }; use asap_types::ir::properties::ExecutionDataStateError; use asap_types::ir::OperatorNode; @@ -303,7 +303,7 @@ impl PlanOutput { /// for [`Stage1ToStage3Pass`] that is Stage 3's selected plan as /// selected (e.g. ingestion-time tumbling windows), the document a deployment /// runtime executes. Only a node the pass left untimed takes the default - /// [`MaterializationAssignment`] (not materialized, computed when its + /// [`PhysicalPropertiesAssignment`] (not materialized, computed when its /// consumer runs). Operator queries become its `roots` and standalone scalar /// queries its `scalar_roots`, keyed by position in the batch. That /// position is the entry index, because `check_contract` requires dense @@ -317,9 +317,9 @@ impl PlanOutput { &self, ) -> Result { // A node several roots share by `Rc` is timed and exported once. - let timed = apply_materialization_timings_to_roots( + let timed = apply_physical_properties_to_roots( &self.roots(), - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), )?; compile_physical_asap_workload(&timed) } diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index 998016695..ea7377231 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -29,7 +29,7 @@ use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::schema_support::with_promql_series_identity; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm, SketchParams}; use asap_types::ir::{ - apply_materialization_timings_to_roots, ASAPOp, MaterializationAssignment, OperatorNode, + apply_physical_properties_to_roots, ASAPOp, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; @@ -1530,7 +1530,7 @@ impl OptimizationPass for StoredAsForced { // Each node untimed once, so shared inputs stay shared, and its // materialization in `assignment`. let mut untimed: HashMap<*const OperatorNode, Rc> = HashMap::new(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); let roots: Vec> = output .plans .iter() @@ -1540,7 +1540,7 @@ impl OptimizationPass for StoredAsForced { // copy per timing, as Stage 2 does. let (roots, assignment) = split_shared_by_timing(&roots, &assignment); let roots: Vec = roots.into_iter().map(QueryRoot::Operator).collect(); - let timed = apply_materialization_timings_to_roots(&roots, &assignment).unwrap(); + let timed = apply_physical_properties_to_roots(&roots, &assignment).unwrap(); for (plan, root) in output.plans.iter_mut().zip(timed) { let QueryRoot::Operator(root) = root else { unreachable!("operator roots in, operator roots out") @@ -1557,7 +1557,7 @@ fn untime( node: &Rc, store: fn(&OperatorNode) -> Option, untimed: &mut HashMap<*const OperatorNode, Rc>, - assignment: &mut MaterializationAssignment, + assignment: &mut PhysicalPropertiesAssignment, ) -> Rc { if let Some(done) = untimed.get(&Rc::as_ptr(node)) { return Rc::clone(done); diff --git a/crates/types/src/ir/mod.rs b/crates/types/src/ir/mod.rs index 026dc620e..99b12a821 100644 --- a/crates/types/src/ir/mod.rs +++ b/crates/types/src/ir/mod.rs @@ -15,8 +15,8 @@ pub mod flat; pub mod materialized_view; pub mod physical_export; pub use properties::timing::{ - apply_materialization_timings, apply_materialization_timings_to_roots, data_state, - is_filtered_build, timing_under_consumer, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, apply_physical_properties_to_roots, data_state, is_filtered_build, + timing_under_consumer, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; #[cfg(any(test, feature = "test-support"))] pub use properties::timing::{planned_data_state, validate_at_ingestion}; diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index 1d691fa7f..59ee2424c 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -92,7 +92,7 @@ impl Operator { /// `schema` and `result_kind` are derived from `operator` and its children /// at construction and retained. `guarantee` is `None` until accuracy /// assessment establishes one (`None` never means exact). `timing` is `None` -/// until a materialization assignment is applied; export rejects an executable +/// until a physical properties assignment is applied; export rejects an executable /// node without one. `lifetime` is how long that assignment keeps this /// node's output (`None` until then, and for every node whose output is not /// kept); with `timing` it is the node's [`crate::physical::PhysicalProperties`]. diff --git a/crates/types/src/ir/physical_export.rs b/crates/types/src/ir/physical_export.rs index 4a1ab49c8..e5bfc5edc 100644 --- a/crates/types/src/ir/physical_export.rs +++ b/crates/types/src/ir/physical_export.rs @@ -2,7 +2,7 @@ //! //! The flattened operators of [`super::flat`], plus the lifetime and //! execution timing (data state) of every node and edge. The input must -//! already be timed ([`crate::ir::properties::timing::apply_materialization_timings`]); export +//! already be timed ([`crate::ir::properties::timing::apply_physical_properties`]); export //! reads each node's timing and lifetime and does not re-run //! data-state validation. The deployment executes the plan as given //! (#509 Assumption 8): it does not change lifetime or timing. @@ -26,9 +26,9 @@ use crate::ir::properties::execution_data_state::{ use crate::ir::properties::guarantee::AccuracyGuarantee; #[cfg(any(test, feature = "test-support"))] use crate::ir::properties::timing::{ - apply_materialization_timings_to_roots, MaterializationAssignment, + apply_physical_properties_to_roots, PhysicalPropertiesAssignment, }; -use crate::ir::properties::timing::{data_state, is_materialization_point}; +use crate::ir::properties::timing::{data_state, is_keepable_state_output}; use crate::ir::schema::{FieldDataType, Schema}; use crate::physical::{Lifetime, PhysicalProperties}; @@ -72,7 +72,7 @@ pub struct PhysicalASAPDAGNode { /// Phase is a placement choice for every operator, independent of payload kind. pub output_state: ExecutionDataState, /// How long and where the deployment keeps this node's output: the - /// lifetime the materialization assignment chose for the sub-DAG this + /// lifetime the physical properties assignment chose for the sub-DAG this /// node produces. Any node may be kept (#509 §Materialization); a node /// with no assignment has lifetime `None`. With `output_state.timing` it /// is the node's [`PhysicalProperties`]. @@ -355,7 +355,7 @@ impl PhysicalASAPDAG { /// This DAG's plan with nothing materialized: the same operators, /// summaries and summary parameters, with every sub-DAG /// not kept and so every node at query time (the default - /// [`MaterializationAssignment`]). Node ids are renumbered, and `roots` + /// [`PhysicalPropertiesAssignment`]). Node ids are renumbered, and `roots` /// and `scalar_roots` keep their order. /// /// The correctness reference of a selected plan: a deployment runtime @@ -366,7 +366,7 @@ impl PhysicalASAPDAG { pub fn with_every_node_at_query_time(&self) -> Result { let roots = self.untimed_query_roots()?; let timed = - apply_materialization_timings_to_roots(&roots, &MaterializationAssignment::default())?; + apply_physical_properties_to_roots(&roots, &PhysicalPropertiesAssignment::default())?; Ok(compile_physical_asap_workload(&timed)?) } @@ -606,7 +606,7 @@ impl PhysicalASAPDAG { // is not kept runs when its consumer runs. let timing = node.output_state.timing; if PhysicalProperties::new(timing, node.lifetime).is_err() - || (is_materialization_point(&node.payload) + || (is_keepable_state_output(&node.payload) && node.lifetime == Lifetime::None && timing != ExecutionTiming::QueryTime) { @@ -840,7 +840,7 @@ pub fn compile_physical_asap_dag( } /// Export the timed DAG below `root`. Every reachable node must carry a -/// timing (see [`crate::ir::properties::timing::apply_materialization_timings`]); the data-state +/// timing (see [`crate::ir::properties::timing::apply_physical_properties`]); the data-state /// rules were checked by that pass and are not re-run here. #[cfg(any(test, feature = "test-support"))] pub(crate) fn compile_physical_asap_dag_with_node_ids( diff --git a/crates/types/src/ir/properties/execution_data_state.rs b/crates/types/src/ir/properties/execution_data_state.rs index 6a1e23b42..35f421ba3 100644 --- a/crates/types/src/ir/properties/execution_data_state.rs +++ b/crates/types/src/ir/properties/execution_data_state.rs @@ -150,7 +150,7 @@ pub enum ExecutionDataStateError { the other timing", fixed.as_str() )] - MaterializationConflictsWithFixedTiming { + PhysicalPropertiesConflictWithFixedTiming { operator: &'static str, fixed: ExecutionTiming, assigned: PhysicalProperties, @@ -182,11 +182,9 @@ pub enum ExecutionDataStateError { /// query time (#509 Algorithm 3, line 13). #[error("{operator}: upstream of ingestion-time node not at ingestion time")] UpstreamNotAtIngestion { operator: &'static str }, - /// A node reached by export without a timing: the materialization timing pass + /// A node reached by export without a timing: the physical properties pass /// was not applied to the DAG first. - #[error( - "{operator} node has no execution timing; apply materialization timings before export" - )] + #[error("{operator} node has no execution timing; apply physical properties before export")] UntimedNode { operator: &'static str }, /// The exported physical DAG failed its own validation, e.g. an empty /// batch or a hand-timed plan the timing pass would have rejected. diff --git a/crates/types/src/ir/properties/mod.rs b/crates/types/src/ir/properties/mod.rs index 455a489f2..b96541f06 100644 --- a/crates/types/src/ir/properties/mod.rs +++ b/crates/types/src/ir/properties/mod.rs @@ -8,7 +8,7 @@ //! - [`execution_data_state`] — when a node's value is produced //! ([`ExecutionTiming`]) and what its edge carries ([`ExecutionDataState`]). //! - [`timing`] — execution timing written into every node from a -//! materialization assignment, and its validation. +//! physical properties assignment, and its validation. //! - [`summary_coverage`] — what a summary state covers. pub mod accuracy; pub mod execution_data_state; diff --git a/crates/types/src/ir/properties/summary_coverage.rs b/crates/types/src/ir/properties/summary_coverage.rs index 5cf1812ed..f371a9931 100644 --- a/crates/types/src/ir/properties/summary_coverage.rs +++ b/crates/types/src/ir/properties/summary_coverage.rs @@ -282,7 +282,7 @@ impl SummaryCoverage { /// A stable identity of `definition`: the 128-bit FNV-1a hash, in hex, /// of its sub-DAG's operators, output kinds and schemas, children /// first, without planning metadata (`timing`, `guarantee`, - /// `materialization`). Two equal definitions (the equality a merge + /// `lifetime`). Two equal definitions (the equality a merge /// requires) get equal ids on any node and in any process, so a summary /// store can key states by this id and a concrete selection. pub(crate) fn definition_id(&self) -> String { diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index f7630c64d..d200a56d1 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -5,10 +5,10 @@ //! The logical DAG carries no timing. Materialization (#509 //! §Materialization) decides, for each sub-DAG, whether its output is kept, //! and if so with which [`PhysicalProperties`]: its timing and its -//! [`Lifetime`] (#1200). [`MaterializationAssignment`] records that per +//! [`Lifetime`] (#1200). [`PhysicalPropertiesAssignment`] records that per //! sub-DAG, named by the node whose output would be kept (any node: a //! summary state, a population, or e.g. the tumbling windows of #509 -//! Example 4), and [`apply_materialization_timings`] expands it into a +//! Example 4), and [`apply_physical_properties`] expands it into a //! timing and a lifetime on every node: //! //! - `SummaryEstimate` and `EvaluatePopulation` run at query time; @@ -29,7 +29,7 @@ //! `FinalizeExactAccumulator` of `finalize_query_candidate`) keeps that //! timing. An explicit assignment on it that agrees is kept; one that needs //! the other timing is an error -//! ([`ExecutionDataStateError::MaterializationConflictsWithFixedTiming`]). +//! ([`ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming`]). //! A root may be kept at ingestion time across evaluations: the query reads //! its stored output. A root of rows that runs at ingestion time without //! being kept there is an error @@ -80,14 +80,14 @@ use crate::physical::{Lifetime, PhysicalProperties}; /// The assignment keeps every assigned node alive, so a later allocation /// cannot reuse its address and match a stale entry. #[derive(Clone, Default)] -pub struct MaterializationAssignment { +pub struct PhysicalPropertiesAssignment { assigned: HashMap<*const OperatorNode, (Rc, Option)>, unassigned: Option, } /// Each assigned node as its operator kind and address, not its whole /// sub-DAG. -impl std::fmt::Debug for MaterializationAssignment { +impl std::fmt::Debug for PhysicalPropertiesAssignment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let assigned: Vec<_> = self .assigned @@ -96,14 +96,14 @@ impl std::fmt::Debug for MaterializationAssignment { (format!("{}@{ptr:p}", node.operator.kind_name()), properties) }) .collect(); - f.debug_struct("MaterializationAssignment") + f.debug_struct("PhysicalPropertiesAssignment") .field("assigned", &assigned) .field("unassigned", &self.unassigned) .finish() } } -impl MaterializationAssignment { +impl PhysicalPropertiesAssignment { /// Every `SummaryAgg` or `MaintainPopulation` not [`set`](Self::set) /// explicitly takes `kept` where the DAG allows it: an ingestion-time /// default over a sub-DAG that can only run at query time leaves that @@ -167,7 +167,7 @@ impl MaterializationAssignment { /// Whether `operator`'s output is a sub-DAG output that materialization may /// store: a `SummaryAgg`, a `SummaryTumblingWindowChain` or a `MaintainPopulation`. -pub(crate) fn is_materialization_point(operator: &Operator) -> bool { +pub(crate) fn is_keepable_state_output(operator: &Operator) -> bool { matches!( operator, Operator::ASAP( @@ -196,7 +196,7 @@ pub fn is_filtered_build(node: &OperatorNode) -> bool { ) } -/// Cache of one [`apply_materialization_timings`] pass: `input node → timed node`, +/// Cache of one [`apply_physical_properties`] pass: `input node → timed node`, /// shared by every root of a workload so a node shared by two roots stays /// one `Rc`. Re-reaching a node with a different timing is a conflict. #[derive(Default)] @@ -244,7 +244,7 @@ pub fn data_state(node: &OperatorNode) -> Option { /// at query time. fn forces_query_time( node: &OperatorNode, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, seen: &mut HashMap<*const OperatorNode, bool>, ) -> bool { let key = node as *const OperatorNode; @@ -261,11 +261,11 @@ fn forces_query_time( Operator::ASAP(ASAPOp::SummaryEstimate { .. }) | Operator::ASAP(ASAPOp::EvaluatePopulation { .. }) => true, _ if node.timing.is_none() - && (is_materialization_point(&node.operator) || assignment.get(node).is_some()) => + && (is_keepable_state_output(&node.operator) || assignment.get(node).is_some()) => { let upstream = upstream(seen); match assignment.resolve(node, upstream) { - Ok(None) if !is_materialization_point(&node.operator) => upstream, + Ok(None) if !is_keepable_state_output(&node.operator) => upstream, Ok(None) => true, Ok(Some(kept)) => kept.timing() == ExecutionTiming::QueryTime, Err(_) => true, @@ -290,9 +290,9 @@ fn forces_query_time( /// Write the timings of `assignment` into every node reachable from `root`, /// top-down, then validate every edge. Returns the timed copy of `root`; /// `cache` carries the sharing across the roots of one workload. -pub fn apply_materialization_timings( +pub fn apply_physical_properties( root: &Rc, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, cache: &mut NodeToTimedNodeCache, ) -> Result, ExecutionDataStateError> { let mut forced = HashMap::new(); @@ -317,25 +317,25 @@ pub fn apply_materialization_timings( Ok(timed) } -/// [`apply_materialization_timings`] over every root of one workload with +/// [`apply_physical_properties`] over every root of one workload with /// one cache, so a node several roots share is timed once and stays one /// node. A standalone scalar root has each operator it reads timed, and is /// rebuilt over the timed nodes. -pub fn apply_materialization_timings_to_roots( +pub fn apply_physical_properties_to_roots( roots: &[QueryRoot], - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, ) -> Result, ExecutionDataStateError> { let mut cache = NodeToTimedNodeCache::new(); roots .iter() .map(|root| { Ok(match root { - QueryRoot::Operator(node) => QueryRoot::Operator(apply_materialization_timings( - node, assignment, &mut cache, - )?), + QueryRoot::Operator(node) => { + QueryRoot::Operator(apply_physical_properties(node, assignment, &mut cache)?) + } QueryRoot::Scalar(expr) => { for node in expr.operator_refs() { - apply_materialization_timings(node, assignment, &mut cache)?; + apply_physical_properties(node, assignment, &mut cache)?; } QueryRoot::Scalar(expr.map_operator_refs(&mut |node| { Rc::clone(cache.timed(node).expect("scalar reference was timed")) @@ -347,7 +347,7 @@ pub fn apply_materialization_timings_to_roots( } /// Validate the sub-DAG below `root` with every sub-DAG kept at ingestion time -/// where the DAG allows it ([`MaterializationAssignment::with_default`]) and +/// where the DAG allows it ([`PhysicalPropertiesAssignment::with_default`]) and /// `root` consumed at `root_timing`. For planning-time legality checks of a /// candidate before it is assembled into a workload DAG: a candidate must stay /// executable if materialization later puts its states at ingestion time. @@ -384,8 +384,8 @@ pub fn planned_data_state( /// The assignment of [`validate_at_ingestion`] and [`planned_data_state`]. #[cfg(any(test, feature = "test-support"))] -fn all_at_ingestion() -> MaterializationAssignment { - MaterializationAssignment::with_default(Some( +fn all_at_ingestion() -> PhysicalPropertiesAssignment { + PhysicalPropertiesAssignment::with_default(Some( PhysicalProperties::new( ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory), @@ -406,7 +406,7 @@ fn kept_at_ingestion(node: &OperatorNode) -> bool { fn placement( node: &Rc, consumer: ExecutionTiming, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, forced: &mut HashMap<*const OperatorNode, bool>, ) -> Result<(ExecutionTiming, Lifetime), ExecutionDataStateError> { // A placement fixed when the candidate was built (an exact-state read @@ -433,7 +433,7 @@ fn placement( // an error. return match assignment.get(node) { Some(Some(kept)) if kept.timing() != placed => Err( - ExecutionDataStateError::MaterializationConflictsWithFixedTiming { + ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: node.operator.kind_name(), fixed: placed, assigned: kept, @@ -455,10 +455,10 @@ fn placement( Some(Some(kept)) => (ExecutionTiming::QueryTime, kept.lifetime()), Some(None) | None => (ExecutionTiming::QueryTime, Lifetime::None), }, - _ if is_materialization_point(&node.operator) || assignment.get(node).is_some() => { + _ if is_keepable_state_output(&node.operator) || assignment.get(node).is_some() => { let upstream = upstream_at_query_time(forced); match assignment.resolve(node, upstream)? { - None if !is_materialization_point(&node.operator) => (consumer, Lifetime::None), + None if !is_keepable_state_output(&node.operator) => (consumer, Lifetime::None), // A summary build that is not kept runs at query time. None => (ExecutionTiming::QueryTime, Lifetime::None), Some(kept) => (kept.timing(), kept.lifetime()), @@ -469,16 +469,16 @@ fn placement( } /// The timing `node` takes when its consumer runs at `consumer`, by the -/// placement rules [`apply_materialization_timings`] applies, for Stage 2's +/// placement rules [`apply_physical_properties`] applies, for Stage 2's /// `split_shared_by_timing`: an assignment that cannot be honored is -/// reported later by [`apply_materialization_timings`]. +/// reported later by [`apply_physical_properties`]. /// `query_time_forced` caches, per node, whether something at or below it /// can only run at query time: pass an empty map and reuse it across the /// calls of one assignment. pub fn timing_under_consumer( node: &Rc, consumer: ExecutionTiming, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, query_time_forced: &mut HashMap<*const OperatorNode, bool>, ) -> ExecutionTiming { placement(node, consumer, assignment, query_time_forced) @@ -488,7 +488,7 @@ pub fn timing_under_consumer( fn write( node: &Rc, consumer: ExecutionTiming, - assignment: &MaterializationAssignment, + assignment: &PhysicalPropertiesAssignment, cache: &mut NodeToTimedNodeCache, forced: &mut HashMap<*const OperatorNode, bool>, ) -> Result, ExecutionDataStateError> { @@ -994,7 +994,7 @@ mod tests { /// Apply with every sub-DAG kept at ingestion time where the DAG allows it, the /// placement whose edge rules these tests exercise. fn apply(root: &Rc) -> Result, ExecutionDataStateError> { - apply_materialization_timings(root, &all_at_ingestion(), &mut NodeToTimedNodeCache::new()) + apply_physical_properties(root, &all_at_ingestion(), &mut NodeToTimedNodeCache::new()) } const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); @@ -1018,9 +1018,9 @@ mod tests { #[test] fn default_assignment_materializes_nothing() { let summary = agg(scan(), kll()); - let root = apply_materialization_timings( + let root = apply_physical_properties( &summary, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -1043,14 +1043,11 @@ mod tests { ExecutionTiming::QueryTime, ), ] { - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&summary, kept(timing, lifetime)); - let root = apply_materialization_timings( - &summary, - &assignment, - &mut NodeToTimedNodeCache::new(), - ) - .unwrap(); + let root = + apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); assert_eq!(root.timing, Some(timing)); assert_eq!(root.lifetime, lifetime); assert_eq!(child(&root).timing, Some(timing)); @@ -1065,10 +1062,10 @@ mod tests { fn ingestion_time_node_over_query_time_upstream_is_rejected() { let inner = agg(scan(), exact_sum()); let outer = agg(Rc::clone(&inner), kll()); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&outer, at_ingestion()); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &estimate(outer), &assignment, &mut NodeToTimedNodeCache::new() @@ -1081,7 +1078,7 @@ mod tests { assignment.set(&inner, at_ingestion()); let outer = agg(Rc::clone(&inner), kll()); assignment.set(&outer, at_ingestion()); - let root = apply_materialization_timings( + let root = apply_physical_properties( &estimate(outer), &assignment, &mut NodeToTimedNodeCache::new(), @@ -1119,7 +1116,7 @@ mod tests { let outer = agg(Rc::clone(&inner), kll()); let mut assignment = all_at_ingestion(); assignment.set(&inner, None); - let root = apply_materialization_timings( + let root = apply_physical_properties( &estimate(outer), &assignment, &mut NodeToTimedNodeCache::new(), @@ -1225,9 +1222,9 @@ mod tests { .unwrap(), ); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &estimate(agg(finalize, kll())), - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new() ) .err(), @@ -1244,11 +1241,10 @@ mod tests { fn any_node_may_be_materialized() { let tumbling_windows = max(scan()); let root = max(Rc::clone(&tumbling_windows)); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&tumbling_windows, at_ingestion()); - let timed = - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(child(&timed).lifetime, KEPT_ACROSS); assert_eq!(child(&timed).timing, Some(ExecutionTiming::IngestionTime)); @@ -1258,10 +1254,10 @@ mod tests { ); let over_evaluation = max(estimate(agg(scan(), kll()))); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&over_evaluation, at_ingestion()); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &over_evaluation, &assignment, &mut NodeToTimedNodeCache::new() @@ -1307,10 +1303,10 @@ mod tests { ) .with_guarantee(None), ); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&filtered, at_ingestion()); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &estimate(Rc::clone(&filtered)), &assignment, &mut NodeToTimedNodeCache::new() @@ -1356,23 +1352,21 @@ mod tests { .with_timing(Some(ExecutionTiming::QueryTime)), ); let stored = Lifetime::OneEvaluation(Medium::Disk); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&read, kept(ExecutionTiming::QueryTime, stored)); - let timed = - apply_materialization_timings(&read, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&read, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(timed.lifetime, stored); assert_eq!(exported(&timed, "FinalizeExactAccumulator"), stored); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&state, at_ingestion()); assignment.set(&read, at_ingestion()); assert_eq!( - apply_materialization_timings(&read, &assignment, &mut NodeToTimedNodeCache::new()) - .err(), + apply_physical_properties(&read, &assignment, &mut NodeToTimedNodeCache::new()).err(), Some( - ExecutionDataStateError::MaterializationConflictsWithFixedTiming { + ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, assigned: at_ingestion().unwrap(), @@ -1385,7 +1379,7 @@ mod tests { /// its whole sub-DAG. #[test] fn debug_names_each_assigned_node_by_its_kind() { - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&agg(scan(), kll()), at_ingestion()); let text = format!("{assignment:?}"); assert!(text.contains("SummaryAgg@"), "{text}"); @@ -1402,13 +1396,12 @@ mod tests { ExecutionTiming::QueryTime, Lifetime::OneEvaluation(Medium::Memory), ); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&fixed, at_query); assert_eq!( - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .err(), + apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()).err(), Some( - ExecutionDataStateError::MaterializationConflictsWithFixedTiming { + ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "Aggregate", fixed: ExecutionTiming::IngestionTime, assigned: at_query.unwrap(), @@ -1421,18 +1414,17 @@ mod tests { /// fixed agrees with either timing: the node keeps its fixed timing and /// records not kept. #[test] - fn explicit_not_materialized_keeps_a_fixed_timing() { + fn explicit_not_kept_keeps_a_fixed_timing() { let read = Rc::new( (*finalize(agg(scan(), exact_sum()))) .clone() .with_timing(Some(ExecutionTiming::QueryTime)), ); let root = max(Rc::clone(&read)); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&read, None); - let timed = - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); let read = child(&timed); assert_eq!(read.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(read.lifetime, Lifetime::None); @@ -1446,9 +1438,9 @@ mod tests { let rows = placed_at_ingestion(max(scan())); let summary = agg(Rc::clone(&rows), kll()); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &summary, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new() ) .err(), @@ -1460,10 +1452,10 @@ mod tests { ) ); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&rows, at_ingestion()); let timed = - apply_materialization_timings(&summary, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(child(&timed).lifetime, KEPT_ACROSS); @@ -1476,9 +1468,9 @@ mod tests { let state = placed_at_ingestion(agg(scan(), exact_sum())); let summary = agg(Rc::clone(&state), kll()); assert_eq!( - apply_materialization_timings( + apply_physical_properties( &summary, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new() ) .err(), @@ -1490,10 +1482,10 @@ mod tests { ) ); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&state, at_ingestion()); let timed = - apply_materialization_timings(&summary, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); assert_eq!(child(&timed).lifetime, KEPT_ACROSS); @@ -1505,31 +1497,28 @@ mod tests { #[test] fn a_root_may_be_stored_at_ingestion_time() { let root = max(scan()); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&root, at_ingestion()); - let timed = - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); assert_eq!(exported(&timed, "Aggregate"), KEPT_ACROSS); let state = agg(scan(), exact_sum()); let root = finalize(Rc::clone(&state)); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set(&state, at_ingestion()); assignment.set(&root, at_ingestion()); - let timed = - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); assert_eq!(exported(&timed, "FinalizeExactAccumulator"), KEPT_ACROSS); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); let root = placed_at_ingestion(max(scan())); assignment.set(&root, None); assert_eq!( - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .err(), + apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()).err(), Some(ExecutionDataStateError::UnstoredIngestionRoot { operator: "Aggregate" }) diff --git a/crates/types/src/physical/workload_plan.rs b/crates/types/src/physical/workload_plan.rs index 42d938810..08f693bf6 100644 --- a/crates/types/src/physical/workload_plan.rs +++ b/crates/types/src/physical/workload_plan.rs @@ -1,4 +1,4 @@ -//! One evaluated materialization assignment rebuilt as a physical DAG. +//! One evaluated physical properties assignment rebuilt as a physical DAG. use std::collections::BTreeMap; use crate::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; @@ -19,7 +19,7 @@ pub struct PhysicalWorkloadPlan { /// exports. pub roots: Vec, pub dag: PhysicalASAPDAG, - /// Its materialization assignment: the lifetime chosen for each summary + /// Its physical properties assignment: the lifetime chosen for each summary /// build (`SummaryAgg` or `SummaryTumblingWindowChain`) of `dag`, by node id, including /// the builds not kept (`Lifetime::None`), and each other node kept /// (a shared node built once per evaluation). A build one query reads diff --git a/crates/types/src/stages/physical/graph.rs b/crates/types/src/stages/physical/graph.rs index c4537eaa4..62867c49a 100644 --- a/crates/types/src/stages/physical/graph.rs +++ b/crates/types/src/stages/physical/graph.rs @@ -25,10 +25,10 @@ pub enum ReaderConstraint { query_outputs: Vec>, minimum: usize, }, - /// A non-summary query materialization: each node produces an + /// A non-summary node kept for one evaluation (`OneEvaluation`): each node produces an /// output reference, or has an immediate selected consumer reached by /// at most one query (`query_outputs` as in `MinimumQueryReaders`). - HighestSharedQueryMaterialization { + HighestSharedOneEvaluation { candidate: PhysicalCandidateId, query_outputs: Vec>, }, @@ -50,7 +50,7 @@ impl ReaderConstraint { pub fn candidate(&self) -> PhysicalCandidateId { match self { Self::MinimumQueryReaders { candidate, .. } - | Self::HighestSharedQueryMaterialization { candidate, .. } + | Self::HighestSharedOneEvaluation { candidate, .. } | Self::AllowedOutputs { candidate, .. } | Self::IncompatibleOutputs { candidate, .. } => *candidate, } @@ -60,7 +60,7 @@ impl ReaderConstraint { pub fn candidate_mut(&mut self) -> &mut PhysicalCandidateId { match self { Self::MinimumQueryReaders { candidate, .. } - | Self::HighestSharedQueryMaterialization { candidate, .. } + | Self::HighestSharedOneEvaluation { candidate, .. } | Self::AllowedOutputs { candidate, .. } | Self::IncompatibleOutputs { candidate, .. } => candidate, } @@ -257,7 +257,7 @@ impl DagOfSelectedCandidates { minimum, .. } => queries_reaching(node, query_outputs) < *minimum, - ReaderConstraint::HighestSharedQueryMaterialization { query_outputs, .. } => { + ReaderConstraint::HighestSharedOneEvaluation { query_outputs, .. } => { !output_nodes.contains(&node) && !consumers[node] .iter() diff --git a/crates/types/tests/materialized_view.rs b/crates/types/tests/materialized_view.rs index 8a6de6150..0ddeffe38 100644 --- a/crates/types/tests/materialized_view.rs +++ b/crates/types/tests/materialized_view.rs @@ -22,9 +22,8 @@ use asap_types::ir::schema::{ SketchParams, SummaryUpdate, }; use asap_types::ir::{ - apply_materialization_timings, apply_materialization_timings_to_roots, ASAPOp, - MaterializationAssignment, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, QueryRoot, - TimeRangeKind, + apply_physical_properties, apply_physical_properties_to_roots, ASAPOp, NodeToTimedNodeCache, + NonASAPOp, Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, TimeRangeKind, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; @@ -93,7 +92,7 @@ fn tumbling_windows_and_kept_merge() -> (PhysicalASAPDAG, usize) { group_by: None, })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, @@ -113,8 +112,7 @@ fn tumbling_windows_and_kept_merge() -> (PhysicalASAPDAG, usize) { .ok(), ); let timed = - apply_materialization_timings(&merge, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + apply_physical_properties(&merge, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); let dag = compile_physical_asap_dag(&timed).unwrap(); let merge_id = dag.roots[0]; (dag, merge_id) @@ -238,7 +236,7 @@ fn three_chains_over_one_scan() -> (PhysicalASAPDAG, PhysicalASAPDAG) { ), chain(&scan, quantile_sketch(SketchAlgorithm::Kll), 60_000, 5), ]; - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); let roots: Vec = chains .iter() .map(|chain| { @@ -260,7 +258,7 @@ fn three_chains_over_one_scan() -> (PhysicalASAPDAG, PhysicalASAPDAG) { ) }) .collect(); - let timed = apply_materialization_timings_to_roots(&roots, &assignment).unwrap(); + let timed = apply_physical_properties_to_roots(&roots, &assignment).unwrap(); let unexpanded = compile_physical_asap_workload(&timed).unwrap(); let expanded = expand_tumbling_window_chains_in_workload(&timed).unwrap(); let mut installed = compile_physical_asap_workload(&expanded.roots).unwrap(); @@ -382,7 +380,7 @@ fn tumbling_windows_of_one_width_form_one_refresh_group() { fn a_shifted_tumbling_window_has_its_own_phase() { let scan = scan_m(); let tumbling_windows = [tumbling_window(&scan, 0), tumbling_window(&scan, 90_000)]; - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, @@ -397,7 +395,7 @@ fn a_shifted_tumbling_window_has_its_own_phase() { .iter() .map(|tumbling_window| QueryRoot::Operator(Rc::clone(tumbling_window))) .collect(); - let timed = apply_materialization_timings_to_roots(&roots, &assignment).unwrap(); + let timed = apply_physical_properties_to_roots(&roots, &assignment).unwrap(); let mut dag = compile_physical_asap_workload(&timed).unwrap(); dag.set_retention(&HashMap::new(), &HashMap::new()).unwrap(); let mut windows: Vec<(u64, u64)> = dag @@ -422,7 +420,7 @@ fn views_of_unbounded_windows_are_groups_of_their_own() { schema: scan_m().schema.clone(), })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); let roots: Vec = [SketchAlgorithm::Kll, SketchAlgorithm::DDSketch] .into_iter() .map(|algorithm| { @@ -446,7 +444,7 @@ fn views_of_unbounded_windows_are_groups_of_their_own() { QueryRoot::Operator(build) }) .collect(); - let timed = apply_materialization_timings_to_roots(&roots, &assignment).unwrap(); + let timed = apply_physical_properties_to_roots(&roots, &assignment).unwrap(); let mut dag = compile_physical_asap_workload(&timed).unwrap(); dag.set_retention(&HashMap::new(), &HashMap::new()).unwrap(); let groups = dag.ingestion_refresh_groups().unwrap(); @@ -470,7 +468,7 @@ fn a_view_reading_a_view_of_its_group_follows_it() { group_by: Some(vec![]), })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); for view in [&tumbling_window, &rollup] { assignment.set( view, @@ -481,11 +479,9 @@ fn a_view_reading_a_view_of_its_group_follows_it() { .ok(), ); } - let timed = apply_materialization_timings_to_roots( - &[QueryRoot::Operator(Rc::clone(&rollup))], - &assignment, - ) - .unwrap(); + let timed = + apply_physical_properties_to_roots(&[QueryRoot::Operator(Rc::clone(&rollup))], &assignment) + .unwrap(); let mut dag = compile_physical_asap_workload(&timed).unwrap(); dag.set_retention(&HashMap::new(), &HashMap::new()).unwrap(); let groups = dag.ingestion_refresh_groups().unwrap(); @@ -530,7 +526,7 @@ fn a_node_above_an_unexpanded_chain_has_the_window_of_its_tumbling_windows() { #[test] fn a_view_has_its_refresh_window_on_a_dag_without_edges() { let view = tumbling_window(&scan_m(), 15_000); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &view, PhysicalProperties::new( @@ -539,8 +535,8 @@ fn a_view_has_its_refresh_window_on_a_dag_without_edges() { ) .ok(), ); - let timed = apply_materialization_timings(&view, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + let timed = + apply_physical_properties(&view, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); let mut dag = compile_physical_asap_dag(&timed).unwrap(); let view_id = dag.roots[0]; let window = Some(RefreshWindow { diff --git a/crates/types/tests/physical_export.rs b/crates/types/tests/physical_export.rs index b87d9499b..4905f2844 100644 --- a/crates/types/tests/physical_export.rs +++ b/crates/types/tests/physical_export.rs @@ -9,8 +9,8 @@ use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::{DataType, Field, FieldDataType, Schema}; use asap_types::ir::schema::{ExactKind, ExactParams, SummaryUpdate}; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, MaterializationAssignment, NodeToTimedNodeCache, - NonASAPOp, Operator, OperatorNode, QueryRoot, + apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, + PhysicalPropertiesAssignment, QueryRoot, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; @@ -48,12 +48,12 @@ const ON_DISK: Lifetime = Lifetime::AcrossEvaluations(Medium::Disk); /// `plan()` timed with its summary kept at ingestion time on disk. fn timed_at_ingestion() -> Rc { let root = plan(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( root.children()[0], PhysicalProperties::new(ExecutionTiming::IngestionTime, ON_DISK).ok(), ); - apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap() + apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap() } /// A summary materialized at ingestion time is read at query time, and the @@ -139,11 +139,11 @@ fn batch_shares_the_summary_and_keeps_one_root_per_query() { child: state, })) .unwrap(); - let assignment = MaterializationAssignment::default(); + let assignment = PhysicalPropertiesAssignment::default(); let mut cache = NodeToTimedNodeCache::new(); let timed: Vec<_> = [first, second] .iter() - .map(|root| apply_materialization_timings(root, &assignment, &mut cache).unwrap()) + .map(|root| apply_physical_properties(root, &assignment, &mut cache).unwrap()) .collect(); let roots: Vec = timed.into_iter().map(QueryRoot::Operator).collect(); let dag = compile_physical_asap_workload(&roots).unwrap(); @@ -158,9 +158,9 @@ fn batch_shares_the_summary_and_keeps_one_root_per_query() { fn scalar_roots_export_in_batch_order_and_reference_nodes() { use asap_types::ir::scalar::ArithmeticOpKind; use asap_types::ir::{ExprSemantics, ScalarExpr}; - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &plan(), - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -278,9 +278,9 @@ fn a_reference_read_twice_is_one_scalar_ref_edge() { child: series("a"), })) .unwrap(); - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &project, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -320,9 +320,9 @@ fn swapped_edge_roles_are_rejected() { right: scan("b"), })) .unwrap(); - let timed = apply_materialization_timings( + let timed = apply_physical_properties( &join, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -392,14 +392,14 @@ fn exports_summary_over_summary_as_typed_precompute_edges() { })) .unwrap(); let mut cache = NodeToTimedNodeCache::new(); - let at_ingestion = MaterializationAssignment::with_default( + let at_ingestion = PhysicalPropertiesAssignment::with_default( PhysicalProperties::new( ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory), ) .ok(), ); - let timed = apply_materialization_timings(&root, &at_ingestion, &mut cache).unwrap(); + let timed = apply_physical_properties(&root, &at_ingestion, &mut cache).unwrap(); let compiled = compile_physical_asap_dag_with_node_ids(&timed).unwrap(); assert_eq!(compiled.node_ids.node_id(&timed), Some(3)); assert_eq!( @@ -523,9 +523,9 @@ fn every_node_at_query_time_keeps_the_operators_and_stores_nothing() { .unwrap() }; let materialized = workload(timed_at_ingestion()); - let at_query_time = apply_materialization_timings( + let at_query_time = apply_physical_properties( &plan(), - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .unwrap(); @@ -584,7 +584,7 @@ fn exported_with_scan( let timed: Vec<_> = roots .into_iter() .map(|root| { - apply_materialization_timings(&root, &MaterializationAssignment::default(), &mut cache) + apply_physical_properties(&root, &PhysicalPropertiesAssignment::default(), &mut cache) .unwrap() }) .map(QueryRoot::Operator) diff --git a/crates/types/tests/schema_rebuilding.rs b/crates/types/tests/schema_rebuilding.rs index 71663330c..ce0a60163 100644 --- a/crates/types/tests/schema_rebuilding.rs +++ b/crates/types/tests/schema_rebuilding.rs @@ -255,16 +255,16 @@ fn current_series_topk() -> Rc { .unwrap() } -/// Time `root` under the default materialization assignment, which runs the +/// Time `root` under the default physical properties assignment, which runs the /// data-state and population-contract validation, and export it. fn compile_physical_asap_dag(root: &Rc) -> Result<(), String> { use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; root.validate_structure().map_err(|e| e.to_string())?; - let timed = apply_materialization_timings( + let timed = apply_physical_properties( root, - &MaterializationAssignment::default(), + &PhysicalPropertiesAssignment::default(), &mut NodeToTimedNodeCache::new(), ) .map_err(|e| format!("{e:?}"))?; @@ -336,11 +336,11 @@ fn a_current_series_population_matches_only_its_selectors_lookback() { /// assignment (not kept by default), while its evaluation always /// runs at query time. #[test] -fn population_timing_follows_its_materialization() { +fn population_timing_follows_its_physical_properties() { use asap_types::ir::physical_export::compile_physical_asap_dag as export_timed; use asap_types::ir::properties::ExecutionTiming::{IngestionTime, QueryTime}; use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; let candidate = current_series_topk(); @@ -351,25 +351,22 @@ fn population_timing_follows_its_materialization() { unreachable!() }; let on_disk = Lifetime::AcrossEvaluations(Medium::Disk); - let mut at_ingestion = MaterializationAssignment::default(); + let mut at_ingestion = PhysicalPropertiesAssignment::default(); at_ingestion.set( population, PhysicalProperties::new(IngestionTime, on_disk).ok(), ); for (assignment, timing, lifetime) in [ ( - MaterializationAssignment::default(), + PhysicalPropertiesAssignment::default(), QueryTime, Lifetime::None, ), (at_ingestion, IngestionTime, on_disk), ] { - let timed = apply_materialization_timings( - &candidate, - &assignment, - &mut NodeToTimedNodeCache::new(), - ) - .unwrap(); + let timed = + apply_physical_properties(&candidate, &assignment, &mut NodeToTimedNodeCache::new()) + .unwrap(); let dag = export_timed(&timed).unwrap(); let [population, evaluation] = &dag.nodes[dag.nodes.len() - 2..] else { unreachable!() diff --git a/crates/types/tests/summary_merge_structure.rs b/crates/types/tests/summary_merge_structure.rs index cc382cb28..773fa16bd 100644 --- a/crates/types/tests/summary_merge_structure.rs +++ b/crates/types/tests/summary_merge_structure.rs @@ -10,8 +10,8 @@ use asap_types::ir::schema::{ StatisticKind, SummaryUpdate, WaveletKind, WaveletParams, }; use asap_types::ir::{ - apply_materialization_timings, ASAPOp, ExprSemantics, MaterializationAssignment, - NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, Predicate, ScalarExpr, + apply_physical_properties, ASAPOp, ExprSemantics, NodeToTimedNodeCache, NonASAPOp, Operator, + OperatorNode, PhysicalPropertiesAssignment, Predicate, ScalarExpr, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; @@ -702,10 +702,9 @@ fn idempotent_families_merge_overlapping_states() { fn summary_merge_timing() { let tumbling_windows = [state(200, "us"), state(200, "eu")]; let root = merge(tumbling_windows.to_vec()).unwrap(); - let timings = |assignment: &MaterializationAssignment| { + let timings = |assignment: &PhysicalPropertiesAssignment| { let timed = - apply_materialization_timings(&root, assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); + apply_physical_properties(&root, assignment, &mut NodeToTimedNodeCache::new()).unwrap(); let children = timed.children(); ( timed.timing.unwrap(), @@ -717,12 +716,12 @@ fn summary_merge_timing() { }; use ExecutionTiming::{IngestionTime, QueryTime}; assert_eq!( - timings(&MaterializationAssignment::default()), + timings(&PhysicalPropertiesAssignment::default()), (QueryTime, vec![QueryTime, QueryTime]) ); let at_ingestion = PhysicalProperties::new(IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory)).ok(); - let mut stored_tumbling_windows = MaterializationAssignment::default(); + let mut stored_tumbling_windows = PhysicalPropertiesAssignment::default(); for tumbling_window in &tumbling_windows { stored_tumbling_windows.set(tumbling_window, at_ingestion); } @@ -732,13 +731,12 @@ fn summary_merge_timing() { ); // A `SummaryAgg` without an assignment runs at query time, so a merge // stored at ingestion time needs its tumbling windows there too. - let mut only_merge = MaterializationAssignment::default(); + let mut only_merge = PhysicalPropertiesAssignment::default(); only_merge.set(&root, at_ingestion); assert!( - apply_materialization_timings(&root, &only_merge, &mut NodeToTimedNodeCache::new()) - .is_err() + apply_physical_properties(&root, &only_merge, &mut NodeToTimedNodeCache::new()).is_err() ); - let mut stored_merge = MaterializationAssignment::with_default(at_ingestion); + let mut stored_merge = PhysicalPropertiesAssignment::with_default(at_ingestion); stored_merge.set(&root, at_ingestion); assert_eq!( timings(&stored_merge), diff --git a/crates/types/tests/tumbling_window_chain.rs b/crates/types/tests/tumbling_window_chain.rs index 76173657f..dd5a89251 100644 --- a/crates/types/tests/tumbling_window_chain.rs +++ b/crates/types/tests/tumbling_window_chain.rs @@ -178,12 +178,12 @@ fn expansion_merges_the_tumbling_windows() { /// tumbling windows: a chain materialized at ingestion time expands into tumbling windows each /// built and stored at ingestion time, over ranges and shifts that run at /// ingestion time too, while the merge reading them stays at query time. -/// An unmaterialized chain expands into query-time tumbling windows. +/// An not_kept chain expands into query-time tumbling windows. #[test] fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ - apply_materialization_timings, MaterializationAssignment, NodeToTimedNodeCache, + apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; let kept_across = Lifetime::AcrossEvaluations(Medium::Memory); @@ -197,7 +197,7 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { query: SketchStatistic::Quantile { q: 0.99 }, })) .unwrap(); - let mut assignment = MaterializationAssignment::default(); + let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &chain, lifetime @@ -205,7 +205,7 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { .then(|| PhysicalProperties::new(timing, lifetime).unwrap()), ); let timed = - apply_materialization_timings(&estimate, &assignment, &mut NodeToTimedNodeCache::new()) + apply_physical_properties(&estimate, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); let expanded = expand_tumbling_window_chains(&timed).unwrap(); let merged = expanded.children()[0]; diff --git a/docs/design_docs/architecture/input-output-workflow.md b/docs/design_docs/architecture/input-output-workflow.md index 400b73675..a3fc422c1 100644 --- a/docs/design_docs/architecture/input-output-workflow.md +++ b/docs/design_docs/architecture/input-output-workflow.md @@ -305,7 +305,7 @@ alternative stays visible in `PlanningRun`. PlanningWorkload + frontend dependencies + PlanningModels -> Stage 0: frontend lowering, one root per normalized query entry -> Stage 1: Pass 1 per-computation candidates, Pass 2 sharing, tumbling windows, reuse - -> Stage 2: one physical candidate per materialization assignment + -> Stage 2: one physical candidate per physical properties assignment -> Stage 3: check, measure and select -> PlanOutput ``` diff --git a/docs/design_docs/architecture/physical-plan-integration.md b/docs/design_docs/architecture/physical-plan-integration.md index e33c876ad..62f1542f1 100644 --- a/docs/design_docs/architecture/physical-plan-integration.md +++ b/docs/design_docs/architecture/physical-plan-integration.md @@ -461,9 +461,9 @@ a numeric entity key is not a score. Exact accumulator inputs are explicitly finalized before row operators consume them. None of these operations proves candidate completeness; that evidence belongs to the semi-join's pruning step. -The logical DAG carries no execution layout: `apply_materialization_timings` +The logical DAG carries no execution layout: `apply_physical_properties` writes each node's timing and lifetime from a -`MaterializationAssignment` before export (no sub-DAG kept by default, so all +`PhysicalPropertiesAssignment` before export (no sub-DAG kept by default, so all query time). The exported DAG carries both, and the deployment executes it as given; this is not a claim that every deployment has implemented every placement. diff --git a/docs/design_docs/architecture/updated_interface_with_pluggable_optimization.md b/docs/design_docs/architecture/updated_interface_with_pluggable_optimization.md index 3011064f3..e4f3e3500 100644 --- a/docs/design_docs/architecture/updated_interface_with_pluggable_optimization.md +++ b/docs/design_docs/architecture/updated_interface_with_pluggable_optimization.md @@ -101,7 +101,7 @@ pub struct QueryPlan { ``` `Stage1ToStage3Pass` returns the selected plan's roots, as Stage 2's realizer -built them with each node's timing and materialization, and with the weight +built them with each node's timing and lifetime, and with the weight proofs Stage 3 made applied; `PlanOutput::physical_asap_dag()` exports them. Physical ASAP-aware optimization decides per sub-DAG whether to materialize, and whether at ingestion or query time, from #604 on. diff --git a/docs/design_docs/concepts/post-asap-ir.md b/docs/design_docs/concepts/post-asap-ir.md index 3e4c5bcda..6e385b356 100644 --- a/docs/design_docs/concepts/post-asap-ir.md +++ b/docs/design_docs/concepts/post-asap-ir.md @@ -81,7 +81,7 @@ Exact work is represented by the ordinary operators, unchanged: - `BinaryOp` combines independently planned operands. Summary planning may set its typed division guards (`checked_finite_division`, `checked_relative_division`); the operator's timing comes from the - materialization assignment, not from the operator. + physical properties assignment, not from the operator. - Aggregate, projection, filter, sort and limit over an evaluation are the ordinary `Aggregate`, `Project`, `Filter`, `Sort` and `Limit` operators reading an ASAP node. Exact-accumulator state may pass through the projection-like @@ -118,13 +118,13 @@ reader), `OneEvaluation(medium)` (kept until every reader of one evaluation finishes) or `AcrossEvaluations(medium)` (kept for later evaluations), with `Medium::Memory` or `Medium::Disk`; an ingestion-time output cannot be kept for `OneEvaluation`. A -[`MaterializationAssignment`](../../../crates/types/src/ir/properties/timing.rs) records, +[`PhysicalPropertiesAssignment`](../../../crates/types/src/ir/properties/timing.rs) records, per sub-DAG, the properties of its kept output, named by the node whose output would be kept. Any node may be named: a summary state, a population, or, as in #509 Example 4, the tumbling windows a query reads. `set(node, Some(properties))` keeps one, `set(node, None)` keeps none, and every other sub-DAG is not kept. Stage 2 chooses the assignment. -`apply_materialization_timings(root, &assignment, &mut NodeToTimedNodeCache)` then writes a +`apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache)` then writes a timing and a lifetime into every node, top-down: - `SummaryEstimate` and `EvaluatePopulation` run at query time; @@ -144,7 +144,7 @@ A node whose timing a candidate builder fixed (the query-time `FinalizeExactAccumulator` read boundary of `finalize_query_candidate`) keeps it: an explicit assignment that agrees with that timing is kept, and one that needs the other timing fails with -`ExecutionDataStateError::MaterializationConflictsWithFixedTiming`; an +`ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming`; an explicit kept output is never silently moved or dropped. A root may be kept at ingestion time, and the query reads its stored output; a root of rows that runs at ingestion time without being stored there fails with @@ -158,7 +158,7 @@ node reached from two consumers that need different timings; assignment is applied. How much a kept output retains (retention) is decided later and is not in the assignment. -`MaterializationAssignment::with_default(kept)` gives every sub-DAG that is +`PhysicalPropertiesAssignment::with_default(kept)` gives every sub-DAG that is not set explicitly `kept` where the DAG allows it; an ingestion-time default over a sub-DAG that can only run at query time leaves that sub-DAG not kept instead of failing (the default applies to @@ -193,7 +193,7 @@ children as edges and no embedded sub-DAGs: producer's data state and grouping/window compatibility. - Each node records `output_state` (timing plus `Raw` or `SummaryState`), `output_schema` and `guarantee`. Export reads the timing written by - `apply_materialization_timings` and rejects an untimed node + `apply_physical_properties` and rejects an untimed node (`ExecutionDataStateError::UntimedNode`); it does not re-run data-state validation. @@ -237,7 +237,7 @@ failure probabilities are combined, and the score guarantee remains in the membership guarantee's child provenance. An exact request does not accept this approximate output path merely because its selected identities are certified. -The materialization assignment decides whether these summaries run at +The physical properties assignment decides whether these summaries run at ingestion time or at query time, and the exported DAG carries that placement. Either placement must give each evaluation a complete rate window and an isolated summary state, or maintain an equivalent replacement diff --git a/docs/design_docs/physical-planning-and-deployment.md b/docs/design_docs/physical-planning-and-deployment.md index 31f34d7a1..fa3a47360 100644 --- a/docs/design_docs/physical-planning-and-deployment.md +++ b/docs/design_docs/physical-planning-and-deployment.md @@ -39,7 +39,7 @@ The Logical Post-ASAP DAG is preceded by the Pre-ASAP DAG, the language-independent query semantics before summary selection. Both are logical `OperatorNode` DAGs. `compile_physical_asap_dag` exports the selected DAG as a `PhysicalASAPDAG`, which is the Physical Plan Compiler's input. Its per-node execution phase (ingestion or query time) is -decided by a `MaterializationAssignment`, as the layer contract below states. +decided by a `PhysicalPropertiesAssignment`, as the layer contract below states. ### Layer contract @@ -50,7 +50,7 @@ decided by a `MaterializationAssignment`, as the layer contract below states. output may be stored (a `SummaryAgg` or a `MaintainPopulation`), whether it is kept and with which timing and `Lifetime` (`None`, `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and records it in - a `MaterializationAssignment`. `apply_materialization_timings` writes every + a `PhysicalPropertiesAssignment`. `apply_physical_properties` writes every node's `ExecutionTiming` and `Lifetime`: a state kept at ingestion time and all of its inputs run at ingestion time; readouts, other consumers, and the other states run at query time. The default assignment keeps nothing; `PlanOutput::physical_asap_dag` applies it @@ -96,7 +96,7 @@ and a feasible candidate that loses on cost. Absence is not a cost comparison. For `sum by(job)(rate(m[1m]))`, Rate remains per series before grouped Sum. `CandidateLogicalASAPDAGs` offers one such candidate, with a per-series Rate state and a grouped -Sum state. Its materialization assignment places it: an ingestion-time Sum state +Sum state. Its physical properties assignment places it: an ingestion-time Sum state finalizes Rate and builds Sum within a bounded precompute run; a query-time Sum over an ingestion-time Rate state leaves the Rate readout and Sum in the query DAG. Storing a value requires its exact evaluation window, revision, readiness and serving @@ -112,7 +112,7 @@ Planner's candidate space decides what to compute, not placement. For an instant-vector PromQL TopK, Planner resolves rows that carry the complete series identity and lists the current-series heap realizations per root with the other candidates, unranked. Precompute or query-time placement of Rate and grouped Sum -is not a separate Planner candidate: the materialization assignment sets +is not a separate Planner candidate: the physical properties assignment sets each node's timing, and the physical compiler reads it. This is the target ownership contract. A backend path that still reconstructs diff --git a/docs/design_docs/proposals/asap-aware-mapping/maintained-populations.md b/docs/design_docs/proposals/asap-aware-mapping/maintained-populations.md index 0975ba578..ffb87c859 100644 --- a/docs/design_docs/proposals/asap-aware-mapping/maintained-populations.md +++ b/docs/design_docs/proposals/asap-aware-mapping/maintained-populations.md @@ -79,9 +79,9 @@ input `EvaluatePopulation` runs at query time. `MaintainPopulation` has no fixed timing: like a `SummaryAgg`, it follows its materialization -(`NotMaterialized`, `MatAtIngestion(medium)` or `MatAtQuery(medium)`, #509 +(`Lifetime::None`, `(IngestionTime, AcrossEvaluations(medium))` or `(QueryTime, OneEvaluation(medium))`, #509 §Materialization), which Stage 2 chooses; it runs at ingestion time only when -it is `MatAtIngestion`. +it is ingestion-time `AcrossEvaluations`. The rule examines compatible workload roots, sets `max_k` to the largest requested k and enables quantile readout if any consumer needs it. It emits a candidate for diff --git a/docs/design_docs/proposals/joint-planning-search.md b/docs/design_docs/proposals/joint-planning-search.md index 713a7e356..2558a5341 100644 --- a/docs/design_docs/proposals/joint-planning-search.md +++ b/docs/design_docs/proposals/joint-planning-search.md @@ -125,17 +125,17 @@ G_KLL += MergeLatest15(G_tumbling_windows) Non-summary query-time materialization must be a query output or have a selected immediate consumer used by only one query; the materialized node itself must have multiple query readers. These connection-dependent constraints match Stage 2's highest-shared-node rule and are enforced in MILP. Summary-state eligibility remains separate. -Physical rules provide executable operators, configurations, and materialization assignments for the generated computations. For example, a supported tumbling window implementation can maintain state at ingestion and merge it at evaluation. This introduces two timing decisions within the same query, rather than one materialization choice for the whole query. Eligibility that depends on consumers is checked against the selected connections; considering every potential consumer at once could incorrectly reject a useful candidate. +Physical rules provide executable operators, configurations, and physical properties assignments for the generated computations. For example, a supported tumbling window implementation can maintain state at ingestion and merge it at evaluation. This introduces two timing decisions within the same query, rather than one materialization choice for the whole query. Eligibility that depends on consumers is checked against the selected connections; considering every potential consumer at once could incorrectly reject a useful candidate. For the running example, assume evaluations occur at aligned minute boundaries and the deployment supports ingestion-time tumbling window maintenance. Stage 2 can expand the state groups as follows; `s` is a generated KLL capacity: ```text -Group Physical candidate Computation Materialization -G_tumbling_windows P_ingest(s) Maintain aligned 1m tumbling windows MatAtIngestion(Memory) -G_KLL K_merge(s) MergeLatest15(G_tumbling_windows) MatAtQuery(Memory) -G_KLL K_build(s) BuildKLL(G_input, 15m) MatAtQuery(Memory) -G95 E95 EstimateQuantile(.95, G_KLL) NotMaterialized -G99 E99 EstimateQuantile(.99, G_KLL) NotMaterialized +Group Physical candidate Computation (timing, lifetime) +G_tumbling_windows P_ingest(s) Maintain aligned 1m tumbling windows (IngestionTime, AcrossEvaluations(Memory)) +G_KLL K_merge(s) MergeLatest15(G_tumbling_windows) (QueryTime, OneEvaluation(Memory)) +G_KLL K_build(s) BuildKLL(G_input, 15m) (QueryTime, OneEvaluation(Memory)) +G95 E95 EstimateQuantile(.95, G_KLL) (QueryTime, None) +G99 E99 EstimateQuantile(.99, G_KLL) (QueryTime, None) ``` `P_ingest(s)` retains the tumbling windows needed to cover the 15m window. `K_merge(s)` constructs window state from those tumbling windows at evaluation; `K_build(s)` instead builds window state from available raw input. Each candidate records its input requirements and costs. The estimators can use either compatible state candidate. Exact and local KLL candidates from Pass 1 also receive supported physical implementations and remain available. Stage 2 has generated choices; it has not yet selected a build or connected an estimator to it. @@ -189,7 +189,7 @@ The following cases make the accounting concrete. Let `B` be the cost of one who | Repeated common evaluations | Both queries evaluate together `n` times; state is discarded after each evaluation. | `n × (B + E95 + E99)`. Selecting one candidate does not mean building only once over the entire horizon. | | Different evaluation timestamps | Q1 evaluates every minute; Q2 every five minutes on the same grid. Both use a 15m window. | Over 15 evaluation ticks, a shareable query-local build executes 15 times, with 15 P95 extractions and 3 P99 extractions: `15B + 15E95 + 3E99`. This assumes sharing at the three common timestamps; an earlier window state cannot automatically answer a later window. | | Ingestion-maintained tumbling windows | One tumbling-window chain feeds a shared query-time merge and both estimators. | Ingestion updates and tumbling-window retention are charged once for the chain. Add `n × (M + E95 + E99)` for `n` common evaluations, plus query-local merge memory. | -| State retained across evaluations | An eligible tumbling-window-chain candidate uses `MatAtQueryKeptAcrossEvaluations(Memory)`. | Charge initial construction, required refresh/update work, retained memory/storage over its lifetime, and evaluation work. Reuse does not eliminate freshness maintenance; generate this case only when supported. | +| State retained across evaluations | An eligible tumbling-window-chain candidate uses `(QueryTime, AcrossEvaluations(Memory))`. | Charge initial construction, required refresh/update work, retained memory/storage over its lifetime, and evaluation work. Reuse does not eliminate freshness maintenance; generate this case only when supported. | | Multiple selected candidates in one group | Some consumers use a small KLL state and others a separate large state. | Charge each selected state's build/update and retention, then each consumer's local work. Equal group identity does not collapse two physical candidates into one charge. | | Shared raw-data retention | Two consumers need 5m and 15m of the same raw source and compatible retention scope. | Both consumers connect to `Retain15m` in `G_raw[d]`. Charge that candidate once; reads and intermediate KLL state have separate owners. | | Per-request overhead | Two requests share computation but still require separate response handling. | Report fixed overhead as `Σ_q N_q × h_q`; omit this constant from the optimization objective but retain its applicable resource usage. Decision-dependent overhead stays in the optimization model. | diff --git a/docs/design_docs/proposals/planner-layering-example1-acceptance.md b/docs/design_docs/proposals/planner-layering-example1-acceptance.md index c66cd3aa6..0dd10ff90 100644 --- a/docs/design_docs/proposals/planner-layering-example1-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example1-acceptance.md @@ -19,7 +19,7 @@ whose expectation needs a feature that is not in the stack yet is |---|---|---| | Query-language frontends | 1 workload `LogicalDAG` | same | | Logical ASAP-aware optimization | Pass 1 (3) × identical-expression rule (2) × window-composition rule (3 × 3) = **54** | Pass 1 (3), each with 2 identical-expression candidates and 6 window-composition candidates (Q1's rate and Q2's option in six 10-s tumbling windows, alone or both, each also with a shared scan) = **27**. Sliding windows are not implemented. | -| Physical ASAP-aware optimization | Materialization options per window form = **156** | Physical operator implementation, plus materialization: each logical candidate with every sub-DAG `NotMaterialized` (27: the doc's Raw plans, with tumbling windows rebuilt at every refresh), each tumbling-window chain also `MatAtIngestion(Memory)` (30 more), and each shared input built once per evaluation, `MatAtQuery(Memory)`, with every tumbling-window chain at query time (15 more) = **72** | +| Physical ASAP-aware optimization | Physical properties options per window form = **156** | Physical operator implementation, plus materialization: each logical candidate with every sub-DAG `Lifetime::None` (27: the doc's Raw plans, with tumbling windows rebuilt at every refresh), each tumbling-window chain also `(IngestionTime, AcrossEvaluations(Memory))` (30 more), and each shared input built once per evaluation, `(QueryTime, OneEvaluation(Memory))`, with every tumbling-window chain at query time (15 more) = **72** | | Plan selection | 1 plan | 1 plan | Every MVP candidate is one of the doc's candidates: in logical ASAP-aware @@ -100,26 +100,26 @@ The three whole-window candidates without a shared input: | Id | From | Q2 physical operators | Materialization | |---|---|---|---| -| P1 | L1 | sort (partition by job) → limit 10 | all `NotMaterialized` | -| P10 | L10 | CMS + heap build → top-10 estimate | all `NotMaterialized` | -| P19 | L19 | CountSketch + heap build → top-10 estimate | all `NotMaterialized` | +| P1 | L1 | sort (partition by job) → limit 10 | all `Lifetime::None` | +| P10 | L10 | CMS + heap build → top-10 estimate | all `Lifetime::None` | +| P19 | L19 | CountSketch + heap build → top-10 estimate | all `Lifetime::None` | Q1 is the same in all three: scan → range → rate accumulator → sum accumulator, each finalized. Invariants: -* Every logical candidate keeps its all-`NotMaterialized` physical candidate, +* Every logical candidate keeps its all-`Lifetime::None` physical candidate, and none is pruned, so no candidate is dropped before plan selection. A logical candidate with `n` tumbling-window chains has 2ⁿ physical candidates: each - chain `NotMaterialized` or `MatAtIngestion(Memory)` (ids `P-m`). + chain `Lifetime::None` or `(IngestionTime, AcrossEvaluations(Memory))` (ids `P-m`). Only tumbling-window chains are placed at ingestion time; Q1's rate tumbling windows may be, because continuously ingesting PromQL data is taken to arrive in time order per series. A logical candidate with a shared input has one more: the highest node both queries read (the scan, or the time range above - it) `MatAtQuery(Memory)`, with every chain at query time. A chain at + it) `(QueryTime, OneEvaluation(Memory))`, with every chain at query time. A chain at ingestion time leaves one query reading the input at query time, so - the input stays `NotMaterialized` there. + the input stays `Lifetime::None` there. * Each physical candidate keeps its logical Q2 option and input sharing. * Exact top-*k* is implemented as a sort followed by a limit: each job's series sorted by the ranked value, descending, then a `Project` that @@ -128,7 +128,7 @@ Invariants: returns each job's `k` heaviest series, and a `Project` to `[job, topk_10]` followed by each ranked series' identity. There is no merge node, because there are no window summaries. -* In the whole-window candidates, every node is `NotMaterialized` and runs +* In the whole-window candidates, every node is `Lifetime::None` and runs at query time. ## Plan selection: 1 plan @@ -137,7 +137,7 @@ Invariants: |---|---|---| | P3-m1 | selected | all exact over one time range built once per evaluation for both queries, at 4.38 per second (cost model 1) | | P2-m1 | valid · costlier | all exact over one scan built once per evaluation, at 4.78 per second: each query still reads its own 1 m time range | -| P1, P2, P3 | valid · costlier | all exact at 7.01 per second, with separate inputs (P1) or a `NotMaterialized` shared scan (P2) or scan and range (P3), charged once per query; they tie with each other up to rounding | +| P1, P2, P3 | valid · costlier | all exact at 7.01 per second, with separate inputs (P1) or a `Lifetime::None` shared scan (P2) or scan and range (P3), charged once per query; they tie with each other up to rounding | | P10 | invalid | Count-Min + heap: a top-*k* output has no guarantee (a heap's bound is per item frequency, not top-*k* membership), and the deployment has no evidence that it meets the target | | P19 | invalid | CountSketch + heap: the same reason | @@ -155,7 +155,7 @@ Invariants: reason, and marked invalid or valid but costlier. * Only valid candidates are priced. Each valid candidate's cost has one entry per DAG node, and `cost_per_second` is their sum. A materialized node is charged - once. A `NotMaterialized` node is charged once per consumer that reads it + once. A `Lifetime::None` node is charged once per consumer that reads it (its multiplier), where a consumer is a query or a materialized node and a read stops at materialized nodes. `stage3_plan_selection_charging_helper_*` check the helper on a hand-built candidate with a @@ -185,13 +185,13 @@ per evaluation, within its 100 ms. deployment evidence every heap candidate is invalid and the exact plan is selected. 4. **Physical ASAP-aware optimization is materialization in the doc's - example.** Example 1 lists only window-form and materialization options. + example.** Example 1 lists only window-form and physical properties options. The planner also reads "physical operator implementation" from the physical ASAP-aware optimization section ("TopK as a sort followed by a limit"), and enumerates materialization for summary builds and shared - inputs: each tumbling-window chain is `NotMaterialized` or `MatAtIngestion(Memory)`, - and the highest node both queries read is `NotMaterialized` or - `MatAtQuery(Memory)`. + inputs: each tumbling-window chain is `Lifetime::None` or `(IngestionTime, AcrossEvaluations(Memory))`, + and the highest node both queries read is `Lifetime::None` or + `(QueryTime, OneEvaluation(Memory))`. 5. **Where exact top-*k* becomes sort + limit.** The Pass 1 diagram draws exact Q2 as "sort + limit 10 per job", but the frontend emits `Aggregate{[TopK]}` and the physical ASAP-aware optimization section calls @@ -201,9 +201,9 @@ per evaluation, within its 100 ms. column" without naming the inner sketch. The test assumes `HydraCms`. 7. **"Shared summary charged once"** does not apply literally: the doc says no summary is shared in Example 1. Plan selection charges a - `NotMaterialized` node once per consuming query and a materialized one - once; the tests check that rule. A `NotMaterialized` shared input - therefore saves nothing here; built once per evaluation (`MatAtQuery`), + `Lifetime::None` node once per consuming query and a materialized one + once; the tests check that rule. A `Lifetime::None` shared input + therefore saves nothing here; built once per evaluation (`OneEvaluation`), it is read once, and that candidate (the doc's "Raw with a shared input") is selected. 8. **Latency.** The doc says an exact top 10 rebuilt at every refresh "may diff --git a/docs/design_docs/proposals/planner-layering-example2-acceptance.md b/docs/design_docs/proposals/planner-layering-example2-acceptance.md index cbb2214e7..57b6de0f3 100644 --- a/docs/design_docs/proposals/planner-layering-example2-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example2-acceptance.md @@ -48,8 +48,8 @@ workload itself. | Query-language frontends | One summary-free DAG: `Distinct`, `Entropy`, `L2` over `flows.src_ip`, last 1 m | Same. Q1 is a distinct count; Q2 is `Entropy` and Q3 is `L2` over the per-source counts, each with an exact population count for the empty-input NULL. | | Logical ASAP-aware optimization, Pass 1 | Each computation: exact, a specialized summary, UnivMon. 3 × 3 × 3 = **27** | Q1: exact, HLL, KMV, UnivMon (no Theta: `asap_sketchlib` has no Theta sketch). Q2, Q3: exact, UnivMon (no specialized entropy or norm summary). 4 × 2 × 2 = **16** | | Logical ASAP-aware optimization, Pass 2 | Summary-capability rule: + 1 (one UnivMon for all three, sized for ε = 0.01) + 9 (3 pairs share a UnivMon × 3 options of the third). Independent kept. **37**. Window composition left out. | Identical-expression rule (Q2 and Q3's shared per-source count, and the shared scan) and summary-capability rule (one UnivMon for two of the queries or all three, sized with each parameter's largest value among its readers): **82** | -| Physical ASAP-aware optimization | Same options as Example 1: no window form → rebuilt from raw samples each refresh. | Each logical candidate with every sub-DAG `NotMaterialized`, plus `MatAtQuery(Memory)` for each summary build two or more queries read: **184** | -| Plan selection | One UnivMon sized for ε = 0.01 vs three separate summaries; the shared one usually wins (one update per flow record instead of three). | 164 invalid: HLL or UnivMon for Q1 (120), whose bound has failure probability None without a distinct bound for `flows`, and UnivMon for Q2 (44), whose entropy has no guarantee. 20 valid. Under cost model 1, KMV for Q1 with the other two exact (P33) costs 6.097 per second and P1, all exact, 6.104, the exact distinct count's values held while Q1 runs; the shared per-source count costs 7.46 rebuilt for each query and 7.06 kept `MatAtQuery`; with the shared scan also built once per evaluation, KMV for Q1 (P35-m3) is selected at 5.745, and all exact costs 5.752; UnivMon for Q3 costs 8.09. | +| Physical ASAP-aware optimization | Same options as Example 1: no window form → rebuilt from raw samples each refresh. | Each logical candidate with every sub-DAG `Lifetime::None`, plus `(QueryTime, OneEvaluation(Memory))` for each summary build two or more queries read: **184** | +| Plan selection | One UnivMon sized for ε = 0.01 vs three separate summaries; the shared one usually wins (one update per flow record instead of three). | 164 invalid: HLL or UnivMon for Q1 (120), whose bound has failure probability None without a distinct bound for `flows`, and UnivMon for Q2 (44), whose entropy has no guarantee. 20 valid. Under cost model 1, KMV for Q1 with the other two exact (P33) costs 6.097 per second and P1, all exact, 6.104, the exact distinct count's values held while Q1 runs; the shared per-source count costs 7.46 rebuilt for each query and 7.06 kept `OneEvaluation`; with the shared scan also built once per evaluation, KMV for Q1 (P35-m3) is selected at 5.745, and all exact costs 5.752; UnivMon for Q3 costs 8.09. | ## Invariants and tests @@ -84,12 +84,12 @@ workload itself. | Invariant | Test | Status | |---|---|---| -| Each logical candidate keeps one physical candidate with nothing materialized, plus one per other materialization assignment; none pruned | `stage2_physical_asap_optimization_keeps_every_logical_candidate` | passes | +| Each logical candidate keeps one physical candidate with nothing materialized, plus one per other physical properties assignment; none pruned | `stage2_physical_asap_optimization_keeps_every_logical_candidate` | passes | | The shared UnivMon stays one build read by all three queries | `stage2_physical_asap_optimization_keeps_the_shared_univmon_as_one_build` | passes | Window-composition candidates are out of scope: the doc leaves them out for this example, and a summary with no window form is rebuilt at every refresh -(Example 1's table) unless a shared build is kept `MatAtQuery` within one +(Example 1's table) unless a shared build is kept `OneEvaluation` within one evaluation. ### Plan selection @@ -98,7 +98,7 @@ evaluation. |---|---|---| | One selected id; every other candidate rejected once with a reason | `stage3_plan_selection_selects_one_and_explains_the_rest` | passes | | The selected plan is the cheapest valid one | `stage3_plan_selection_selects_cheapest_valid` | passes | -| Each node of a valid candidate is charged once per consuming query while `NotMaterialized`, once when materialized | `stage3_plan_selection_charges_each_node_per_consuming_query` | passes | +| Each node of a valid candidate is charged once per consuming query while `Lifetime::None`, once when materialized | `stage3_plan_selection_charges_each_node_per_consuming_query` | passes | | No candidate builds a Theta sketch | `stage3_plan_selection_has_no_theta_candidate` | passes | | A UnivMon estimate has a guarantee, so it is judged against its target instead of rejected for having none | `stage3_plan_selection_judges_univmon_with_an_accuracy_model` | ignored: needs a UnivMon entropy accuracy model (#788); L2 and the distinct count have one | | Given a distinct bound for the source, classic HLL's failure probability is bound and Q1's HLL is accepted; a larger bound enlarges its precision, also in a tumbling-window chain | `stage3_plan_selection_accepts_hll_given_a_distinct_bound`, `…_enlarges_hll_for_a_larger_distinct_bound`, `…_enlarges_tumbling_window_hll` | passes | @@ -112,8 +112,8 @@ The doc's "the shared candidate usually wins" depends on the cost model, so it is tested only as the dominance above: one build sized for the strictest consumer costs no more than three builds that include one of that size. Whether it also beats the exact plans is the model's call. The dominance needs the -shared UnivMon materialized: plan selection charges a `NotMaterialized` -node once per consuming query, so unmaterialized it costs three builds of the +shared UnivMon materialized: plan selection charges a `Lifetime::None` +node once per consuming query, so not_kept it costs three builds of the strictest size. ## Ambiguities and conflicts with the planner diff --git a/docs/design_docs/proposals/planner-layering-example3-acceptance.md b/docs/design_docs/proposals/planner-layering-example3-acceptance.md index f6f253b9d..8966edd70 100644 --- a/docs/design_docs/proposals/planner-layering-example3-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example3-acceptance.md @@ -47,7 +47,7 @@ Shared data workload, except Pattern A's `arrival` is `Mixed`. | Query-language frontends | A: five scan → range → quantile chains. B: one. | Same; q3–q5 also have a `time_shift`. | | Logical ASAP-aware optimization, Pass 1 | A: exact or KLL over its own interval per query, 2⁵ = 32. B: exact, KLL. | A: exact, KLL (k = 547), DDSketch per query, 3⁵ = **243**. B: exact, KLL (k = 269), DDSketch, **3**. | | Logical ASAP-aware optimization, Pass 2 | A: window composition adds one EH of KLLs over [T − 5 y, T], one merge + p99 estimate per query, plus a candidate for every grouping of two or more queries onto shared window summaries ("hundreds"). B: each Pass 1 option × {none, sliding L = 5 min s = 1 min (5 active windows), 1-min tumbling (merge 5)} = 6. Independent kept. | Identical-expression rule: each Pass 1 candidate also gets its shared-input candidates (A: 3 per Pass 1 candidate; B: none). Window-composition rule, tumbling windows only: B's KLL and DDSketch each also come as 1-min tumbling windows (a `SummaryTumblingWindowChain` of 5, merged before the p99 estimate), **5** in all; A is run once, so it gets none. No sliding windows or EHs. | -| Physical ASAP-aware optimization | See Example 4. | Each logical candidate with every sub-DAG `NotMaterialized` (A: 972; B: 5), plus, for A, each highest shared input (a scan or a shift) also built once per evaluation, `MatAtQuery(Memory)` (A: 2,187 in all), and, for B, each tumbling-window chain maintained `MatAtIngestion(Memory)` (B: 7 in all). | +| Physical ASAP-aware optimization | See Example 4. | Each logical candidate with every sub-DAG `Lifetime::None` (A: 972; B: 5), plus, for A, each highest shared input (a scan or a shift) also built once per evaluation, `(QueryTime, OneEvaluation(Memory))` (A: 2,187 in all), and, for B, each tumbling-window chain maintained `(IngestionTime, AcrossEvaluations(Memory))` (B: 7 in all). | | Plan selection | Not stated for Example 3. | A: 288 valid, 1,899 invalid: every candidate with a DDSketch misses the rank target (its bound is relative). KLL for all five queries (P485) is selected at 207,189.43 per second (cost model 1); all exact costs 327,132,784.05, about 1,600 times as much, its values held for the whole of each long query. B: KLL (P2, 2.363 per second); the 1-min KLL tumbling windows rebuilt at every evaluation cost 3.611 (the same rows and updates plus merging 5 tumbling windows per series, and the tumbling windows held while the query runs); maintained at ingestion time they keep six tumbling windows of 1,000,000 per-series KLLs for 654.54; exact costs 2.458; DDSketch, whole or in tumbling windows, misses the rank target. Every valid B plan meets 200 ms: 126 ms for the whole-window KLL, 131 ms for the rebuilt tumbling windows, 7 ms for the maintained tumbling windows, 144 ms exact. | ## Invariants and tests @@ -66,7 +66,7 @@ Shared data workload, except Pattern A's `arrival` is `Mixed`. | The EH candidate coexists with the five independent KLLs | `stage1_logical_asap_optimization_a_keeps_independent_and_shared_window_summaries` | ignored: #628, #634 | | Every pair of queries shares a window summary in some candidate | `stage1_logical_asap_optimization_a_window_composition_groups_every_pair` | ignored: #628, #634 | | One selected id, the rest explained; the selected plan is the cheapest valid one | `stage3_plan_selection_a_selects_cheapest_valid` | passes | -| Each node of a valid candidate is charged once per consuming query while `NotMaterialized`, once when materialized | `stage3_plan_selection_a_charges_each_node_per_consuming_query` | passes | +| Each node of a valid candidate is charged once per consuming query while `Lifetime::None`, once when materialized | `stage3_plan_selection_a_charges_each_node_per_consuming_query` | passes | | For the same per-computation choices, sharing the scan costs no more than separate scans | `stage3_plan_selection_a_shared_scan_is_not_costlier` | ignored: #632 (see ambiguity 7) | ### Pattern B diff --git a/docs/design_docs/proposals/planner-layering-example4-acceptance.md b/docs/design_docs/proposals/planner-layering-example4-acceptance.md index ae9371317..54b5e003e 100644 --- a/docs/design_docs/proposals/planner-layering-example4-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example4-acceptance.md @@ -50,12 +50,12 @@ time, both kept. Not materializing it is the no-window plan, so it is not a separate option. **Today:** Pass 2 builds tumbling windows (`SummaryTumblingWindowChain`), and physical -ASAP-aware optimization enumerates `NotMaterialized`, `MatAtIngestion` and -`MatAtQuery` (state reused within one evaluation) for every summary build. +ASAP-aware optimization enumerates `Lifetime::None`, ingestion-time `AcrossEvaluations` and +`OneEvaluation` (state reused within one evaluation) for every summary build. B1 and B2 exist. B3 (tumbling windows built at query time and kept across evaluations) is offered when the deployment declares `query_time_results_retained` in its `deployment_capabilities`: Stage 2 then -adds `MatAtQueryKeptAcrossEvaluations` for a tumbling-window chain that builds +adds query-time `AcrossEvaluations` for a tumbling-window chain that builds one new tumbling window per evaluation. Pattern A's shared EH needs window segments shared across queries (#628, #634), so A1–A3 do not exist yet. B3's 4 kept tumbling windows plus the newest cost 436.59 per second under cost model 1, @@ -63,10 +63,10 @@ between B2 (3.611) and B1 (654.54). ## Invariants and tests -**Reading materialization.** The physical DAG records each node's -`Materialization` (#667). Tests read it through -`planner_layering_common::materialization(p, node)` without the storage -medium (`MatAtIngestion`, `MatAtQuery`, `NotMaterialized`), and the kept +**Reading physical properties.** The physical DAG records each node's +timing and `Lifetime` (#667, #1200). Tests read them through +`planner_layering_common::keeping(p, node)` without the lifetime length or +storage medium (`KeptAtIngestion`, `KeptAtQueryTime`, `NotKept`), and the kept event-time span through `retention_ms(p, node)`. The IR does not record retention, so the adapter derives it the way plan selection prices kept state: a chain of `N` tumbling windows of width `w` keeps `N·w`, plus one tumbling window while @@ -89,7 +89,7 @@ it. | The shared EH yields exactly A1, A2, A3 | `stage2_physical_asap_optimization_a_shared_eh_has_three_materialization_options` | ignored: the shared EH (#628, #634) | | At rest, A2 is not generated; A1 and A3 remain | `stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option` | ignored: the shared EH (#628, #634) | | A materialized EH is one build node read by all five queries, priced once | `stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers` | ignored: the shared EH (#628, #634) | -| A3 costs strictly more than A1 (five builds instead of one: a `NotMaterialized` node is charged per consuming query) | `stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once` | ignored: the shared EH (#628, #634) | +| A3 costs strictly more than A1 (five builds instead of one: a `Lifetime::None` node is charged per consuming query) | `stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once` | ignored: the shared EH (#628, #634) | | As given, A1 is the cheapest of the three | `stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh` | ignored: the shared EH (#628, #634) | | Monthly, A2's cost relative to A1 drops: cost(A2)/cost(A1) monthly < as given | `stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance` | ignored: the shared EH (#628, #634) | @@ -127,11 +127,11 @@ it. 1. **Charging A3 (decided).** A3 is one logical EH node that is not materialized, so it is rebuilt by each of its five consumers. Plan - selection charges a `NotMaterialized` node once per consuming query + selection charges a `Lifetime::None` node once per consuming query (`NodeCost::multiplier`) and a materialized node once; physical ASAP-aware optimization does not duplicate the node. So A3 costs five EH builds and A1 one, as the tests require. The A3 tests stay ignored only because the - shared EH and its materialization options do not exist yet. + shared EH and its physical properties options do not exist yet. 2. **Recurrence input (resolved).** Materialization depends on `recurrence`, `predictability` and `arrival`: `optimize_physical_asap` takes the workload entries (`QueryWorkloadEntry`: recurrence, diff --git a/docs/design_docs/proposals/planner-layering.md b/docs/design_docs/proposals/planner-layering.md index 298b1db0e..7a6dfad7c 100644 --- a/docs/design_docs/proposals/planner-layering.md +++ b/docs/design_docs/proposals/planner-layering.md @@ -600,7 +600,7 @@ the memo path's entry points. | 1, Pass 1 | Logical roots; the deployment's supported summaries → the Pass 1 inventory, every computation's candidates (`PerComputationCandidates`, now Pass 1's crate-private working form) | Logical roots → `DagOfLogicalMemoGroups` (hash-consed `MemoGroup`s); with the Pass 1 inventory, less the summaries the deployment does not support and those no query reading them can use → `PerComputationLogicalMemoCandidates`: the `Memo` (each group's `CandidateForMemoGroup`s, with the accuracy-scoped sizes) and the pruned candidates (`PrunedCandidate`) | `generate_dag_of_logical_memo_groups`, `generate_per_computation_logical_memo_candidates` | | 1, Pass 2 | One Pass 1 choice per computation → that choice rewritten by each sharing rule, every subset of sharing choices (no longer in the code) | `Memo`; the entries' recurrence and range steps → the same memo with each rule's candidates added to the groups they implement | the memo rules (`pass2/memo/rules/`), `pass2::memo::window_candidates` | | 1, concrete summary-state groups | (part of Pass 2) | `Memo` → the memo with concrete summary-state groups: one group per shared size or tumbling-window layout that readers can read | `add_shared_summary_state_groups`, Pass 2's last step; the Pass 2 output is `LogicalASAPMemoCandidates` (`generate_logical_asap_memo_candidates`) | -| 2 | One whole-workload logical candidate; entries (recurrence, predictability), `DataWorkload`, query-time retention → its physical candidates, one per materialization assignment | `LogicalASAPMemoCandidates`; entries, `DataWorkload`, query-time and raw-data retention → `PhysicalASAPMemoCandidates`: every operator node of every candidate with each allowed timing and lifetime (one physical candidate each, no copies), the producers of each input, reader constraints (each applied to every selected run of its candidate), and the pruned candidates (`PrunedCandidate`) | `generate_physical_asap_memo_candidates` (`asap_physical_asap_optimization`) | +| 2 | One whole-workload logical candidate; entries (recurrence, predictability), `DataWorkload`, query-time retention → its physical candidates, one per physical properties assignment | `LogicalASAPMemoCandidates`; entries, `DataWorkload`, query-time and raw-data retention → `PhysicalASAPMemoCandidates`: every operator node of every candidate with each allowed timing and lifetime (one physical candidate each, no copies), the producers of each input, reader constraints (each applied to every selected run of its candidate), and the pruned candidates (`PrunedCandidate`) | `generate_physical_asap_memo_candidates` (`asap_physical_asap_optimization`) | | 3 | Every physical candidate; accuracy targets, accuracy model and evidence, cost model → one plan | `PhysicalASAPMemoCandidates`; entries, `DataWorkload`, `AccuracyCheckInputs`, `CostInputs`, Stage 2's realizer → `Selection`: the selected plan (`selected_dag`, a `DagOfSelectedCandidates`: one node per run of a candidate, so a candidate recomputed by two readers or shared as two instances over different inputs is two nodes, with an edge per input), its cost, the accepted accuracy per query and the search report | `select_plan` (`asap_plan_selection`); the facade (`run_planning`, output `PlanningRun`) runs it once and builds the selected `PhysicalWorkloadPlan` with `AssignmentRealizer::realize`, one plan node per selected node | | 4. Execution | The selected `PhysicalASAPDAG` → query results | Same: an `InstallablePlan` (`{dag, query_texts}`) → query results | The deployment runtime installs the `InstallablePlan` | @@ -1209,7 +1209,7 @@ is offered not kept, kept at ingestion time `AcrossEvaluations(Memory)` when it is eligible to run at ingestion time, and kept at query time `OneEvaluation(Memory)` when two or more queries read it. Of every other sub-DAG that two or more queries read (for example a `Scan` that a 1 m and a -5 m window both read), only the highest node is a materialization candidate: +5 m window both read), only the highest node is a kept-output candidate: one that a query's output, or a node only one query reads, consumes. It is offered not kept and `OneEvaluation(Memory)` only, since raw rows are not maintained at ingestion time. Below an ingestion-time build it stays not @@ -1248,20 +1248,20 @@ Output: C3 — CandidatePhysicalASAPDAGs 2: for each LogicalASAPDAG d in C2 do 3: // Materialization: options per sub-DAG 4: for each sub-DAG s in d do -5: Opt(s) ← { NotMaterialized } +5: Opt(s) ← { (QueryTime, None) } 6: for each medium in {memory, disk} do -7: Opt(s) ← Opt(s) ∪ { MatAtIngestion(medium), MatAtQuery(medium) } +7: Opt(s) ← Opt(s) ∪ { (IngestionTime, AcrossEvaluations(medium)), (QueryTime, OneEvaluation(medium)) } 8: end for 9: end for 10: 11: for each assignment m in Opt(s_1) × … × Opt(s_n) do 12: // constraint: everything upstream of an ingestion-time node also runs at ingestion time -13: if some s with m(s) = MatAtIngestion has an upstream node u with m(u) ≠ MatAtIngestion then +13: if some s with timing(m(s)) = IngestionTime has an upstream node u with timing(m(u)) ≠ IngestionTime then 14: PRUNE(m, "upstream of ingestion-time node not at ingestion time") 15: continue 16: end if 17: // constraint: keep a materialized output as long as any consumer needs it -18: for each s with m(s) ≠ NotMaterialized do +18: for each s with lifetime(m(s)) ≠ None do 19: retention(s) ← latest time any consumer of s reads it // from recurrence, windows 20: end for 21: // a shared summary is one node, so it is materialized once for all consumers @@ -1304,7 +1304,7 @@ into a node. *Example for Algorithm 3* ([Example 4, Pattern B](#example-4-materialization-of-window-summaries-in-physical-planning)). The logical candidate is the `Tumbling(1m)` KLL option from Algorithm 2. The -diagram shows three of its materialization assignments, each drawn as a copy +diagram shows three of its physical properties assignments, each drawn as a copy of the DAG with every node colored by its materialization. Line 13 enforces one rule: a node can run at ingestion time only if every node it reads from also runs at ingestion time, because otherwise its input does not exist yet when @@ -1333,7 +1333,7 @@ flowchart TB end subgraph LEG["Legend: when a node runs and whether its output is stored"] direction LR - l1["MatAtIngestion"]:::ingest ~~~ l2["MatAtQuery"]:::qtime ~~~ l3["NotMaterialized"]:::notmat + l1["(IngestionTime, AcrossEvaluations)"]:::ingest ~~~ l2["(QueryTime, OneEvaluation)"]:::qtime ~~~ l3["(QueryTime, None)"]:::notmat end M1 --> P1 LEG ~~~ M1 diff --git a/docs/design_docs/proposals/window-materialization-choices.md b/docs/design_docs/proposals/window-materialization-choices.md index 7646956cd..026edabfb 100644 --- a/docs/design_docs/proposals/window-materialization-choices.md +++ b/docs/design_docs/proposals/window-materialization-choices.md @@ -22,5 +22,5 @@ A tumbling window is an aligned, non-overlapping fixed-width interval and its ag This table describes possible strategies. Current tumbling window support does not imply general direct sliding-state or EH support. Offer only executable candidates. Multiple tumbling-window widths can coexist; alignment, coverage, mergeability, retention, and error contracts determine legality. A 15m window evaluated every 1m can use 1m tumbling windows; complete 5m tumbling windows alone generally cannot cover every endpoint. -Use existing `Materialization` options: `NotMaterialized`, `MatAtQuery(Memory)`, `MatAtIngestion(Memory)`, and `MatAtQueryKeptAcrossEvaluations(Memory)`. Assign them to eligible internal nodes, not necessarily the entire query. For example, maintain tumbling windows at ingestion and merge at query time. Generate only supported assignments: retained query-time state currently requires deployment capability and an eligible tumbling-window chain. Ingestion timing and upstream dependencies must satisfy Stage 2 rules. +Use existing physical properties: `Lifetime::None`, `(QueryTime, OneEvaluation(Memory))`, `(IngestionTime, AcrossEvaluations(Memory))`, and `(QueryTime, AcrossEvaluations(Memory))`. Assign them to eligible internal nodes, not necessarily the entire query. For example, maintain tumbling windows at ingestion and merge at query time. Generate only supported assignments: retained query-time state currently requires deployment capability and an eligible tumbling-window chain. Ingestion timing and upstream dependencies must satisfy Stage 2 rules. diff --git a/docs/develop_docs/asap-aware-mapping-architecture.md b/docs/develop_docs/asap-aware-mapping-architecture.md index e48219803..6133b66eb 100644 --- a/docs/develop_docs/asap-aware-mapping-architecture.md +++ b/docs/develop_docs/asap-aware-mapping-architecture.md @@ -71,8 +71,8 @@ same pipeline behind the `OptimizationPass` trait. | Pass 2 memo rules: shared producers (identical expressions by memo group identity, one build at different sizes), scan-label widening, window composition (tumbling windows), rollup, exact top-k reuse and finer-aggregate reuse | `asap-logical-asap-optimization`, `pass2/memo/rules/` and `pass2/memo/window_candidates.rs`, over the helpers in `pass2/asap_aware_cse.rs` | | Enumeration of the plans a memo stands for (reference pricer, DAG viewer) | `asap-logical-asap-optimization`, `pass2/memo/enumeration.rs` | | What each summary family can merge and answer (`FamilyCapability::of`: `merge_inputs`, `readouts`) | `asap-types`, `ir/schema/family_capability.rs` | -| Stage 2: materialization options per summary build (not kept; kept at ingestion time `AcrossEvaluations`; kept at query time `OneEvaluation` or `AcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | -| Timing and data-state edge rules applied from a `MaterializationAssignment` | `asap-types`, `ir/properties/timing.rs` and `ir/properties/execution_data_state.rs`; `PhysicalProperties` and `Lifetime` in `physical/properties.rs` | +| Stage 2: physical properties options per summary build (not kept; kept at ingestion time `AcrossEvaluations`; kept at query time `OneEvaluation` or `AcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | +| Timing and data-state edge rules applied from a `PhysicalPropertiesAssignment` | `asap-types`, `ir/properties/timing.rs` and `ir/properties/execution_data_state.rs`; `PhysicalProperties` and `Lifetime` in `physical/properties.rs` | | Stage 3: accuracy check, latency check, resource usage (`ResourceUsage`), cost models 1–3 (`CostModel`), measured operation costs | `asap-plan-selection`, `lib.rs`; `asap-cost`, `lib.rs` and `measured.rs` | | The analytical per-operator resource model Stage 3 measures with | `asap-cost`, `analytical.rs` and `operator_statistics.rs` | | The accuracy algebra: per-family guarantees, composition, budget split; guarantee propagation through a DAG; sizing a summary for its target, (ε, δ) budget and default sizes | `asap-accuracy` (`AccuracyModel`, `BuiltinAccuracyModel`, `estimators/`, `composition.rs`, `budget.rs`, `propagation.rs`, `sizing.rs`) | @@ -98,7 +98,7 @@ The unwired maintained-population rule has been removed as well; no Stage 1 pass For each composed DAG, the Pass 2 rules find what can be shared, split into tumbling windows or reused, and each subset of their candidates becomes another Stage 1 candidate. -3. **Stage 2** gives each summary build its materialization options and emits +3. **Stage 2** gives each summary build its physical properties options and emits one physical candidate per assignment (the all-not-kept one first), skipping assignments that put a build at ingestion time over one that is not. @@ -121,7 +121,7 @@ No stage caps the candidates it plans, and neither does `asap_planner`. Pass 1. - `crates/integration-tests/tests/planner_layering_example{1,2,3,4}.rs` pin the design document's examples through every stage; - `reuse_rules.rs`, `deployment_capabilities.rs`, `materialization_e2e.rs` + `reuse_rules.rs`, `deployment_capabilities.rs`, `physical_properties_e2e.rs` and `stage1_logical_asap_optimization.rs` cover single rules end to end. - `crates/devtools/tests/asap_planner.rs` checks the stage document and the committed viewer examples; `asap_planner_acceptance.rs` checks diff --git a/docs/develop_docs/asap-aware-mapping-contracts.md b/docs/develop_docs/asap-aware-mapping-contracts.md index 775081130..70f6b991b 100644 --- a/docs/develop_docs/asap-aware-mapping-contracts.md +++ b/docs/develop_docs/asap-aware-mapping-contracts.md @@ -15,12 +15,12 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types | --- | --- | --- | | Stage 0 (frontends) | `NonASAPOp` nodes only; aggregates carry `AggIntent` measures with each query's `AccuracyTarget` as written | none | | Stage 1 (`compose_logical_candidate`, Pass 2 rules) | `ASAPOp` nodes where a candidate chose an exact accumulator or a summary (`SummaryAgg`, `SummaryTumblingWindowChain`, `SummaryMerge`, `SummaryEstimate`, `FinalizeExactAccumulator`); everything else stays `NonASAPOp` | none: Stage 1 never decides when anything runs | -| Stage 2 (`generate_physical_asap_memo_candidates`; a selected plan built by `Stage2AssignmentRealizer`) | the same operators, with a timing and a `Lifetime` on each summary build | every node timed from the candidate's `MaterializationAssignment` | +| Stage 2 (`generate_physical_asap_memo_candidates`; a selected plan built by `Stage2AssignmentRealizer`) | the same operators, with a timing and a `Lifetime` on each summary build | every node timed from the candidate's `PhysicalPropertiesAssignment` | - Structurally equal sub-DAGs are interned before Stage 1 (`stage0/cse.rs` in `asap_logical_asap_optimization`), so Stage 1 compares nodes by structure and Pass 2 matches readers structurally, never by pointer. -- Timing is applied with `apply_materialization_timings`, which validates +- Timing is applied with `apply_physical_properties`, which validates every data-state edge. A violation is an `ExecutionDataStateError`: for example `QueryTimeValueUnderIngestionSummary` (a query-time value beneath an ingestion-time build), `ConflictingTiming` (one shared node diff --git a/docs/develop_docs/extend-asap-aware-mapping.md b/docs/develop_docs/extend-asap-aware-mapping.md index 0eff8855e..dd6deb235 100644 --- a/docs/develop_docs/extend-asap-aware-mapping.md +++ b/docs/develop_docs/extend-asap-aware-mapping.md @@ -74,21 +74,21 @@ and when it must not; an end-to-end test like `crates/integration-tests/tests/reuse_rules.rs` that the planned workload contains the candidate and that Stage 3 prices it. -## 3. Add a Stage 2 materialization option +## 3. Add a Stage 2 physical properties option 1. Add the `Lifetime` variant or the valid (timing, lifetime) pair (`crates/types/src/physical/properties.rs`, `PhysicalProperties::new` and `readable_at`) and its placement in `crates/types/src/ir/properties/timing.rs`, with its data-state edge rules. 2. Offer it in `crates/physical-asap-optimization/src/lib.rs` (the - `MaterializationCandidate` options), after the existing options so default + `KeptOutputCandidate` options), after the existing options so default candidate ids stay the same, and gate it on the deployment input that allows it. 3. Price it in `crates/cost/src/usage.rs` (`asap_cost::node_usage`): what it keeps in memory or on disk, and what each evaluation rebuilds. Tests: Stage 2 unit tests for when the option is offered; -`crates/integration-tests/tests/materialization_e2e.rs` and the Example 4 +`crates/integration-tests/tests/physical_properties_e2e.rs` and the Example 4 tests in `planner_layering_example4.rs`. ## 4. Add a Stage 3 check or a deployment input diff --git a/docs/develop_docs/library-api.md b/docs/develop_docs/library-api.md index b70866ccb..020d2961b 100644 --- a/docs/develop_docs/library-api.md +++ b/docs/develop_docs/library-api.md @@ -206,7 +206,7 @@ asap_plan_selection::select_plan( | `PlanOutput.selection` | `Some` with Stage 3's `Selection` under the default pass: `selected_dag`, `nodes_with_proven_non_negative_weights`, `cost` (the selected plan's `PlanCost` with its `ResourceUsage` and `cost_per_second`, `None` under cost model 3), `accepted_accuracy_per_query`, `pruned_candidates` and `search_report` | | `PlanOutput.tumbling_window_retention_ms` | For each tumbling-window chain the selected plan keeps beyond one evaluation, by node id, how long its tumbling windows are kept (`RealizedPlan::tumbling_window_retention_ms`) | | `PlanningRun` | `per_computation_candidates`, `logical_asap_candidates`, `physical_asap_candidates`, `selection`, `selected_physical_plan` (`RealizedPlan`), `selected_plan` (the roots to run) and `report` (Pass 2's and Stage 2's counts and each stage's time); `per_computation_candidates` is kept only with `PlanSearchSettings::inspect`; `asap_planner::selected_chosen_candidates` reads the selected plan as one candidate per group of `logical_asap_candidates.memo` | -| `PlanOutput::physical_asap_dag()` | The planned queries as one `PhysicalASAPDAG`, timed with the default `MaterializationAssignment` (see [Export](#export)) | +| `PlanOutput::physical_asap_dag()` | The planned queries as one `PhysicalASAPDAG`, timed with the default `PhysicalPropertiesAssignment` (see [Export](#export)) | Each candidate's `ResourceUsage` holds its usage without prices: `cpu_ops_per_second`, `scanned_bytes_per_second`, `average_memory_bytes`, @@ -360,7 +360,7 @@ optional also does not guarantee every planning operation can succeed without it | Function/type | Purpose | | --- | --- | -| `asap_types::ir::apply_materialization_timings(&root, &assignment, &mut NodeToTimedNodeCache::new())` | Write execution timing into every node from a `MaterializationAssignment` (default: all query time) and validate the data-state edges; `PlanOutput::physical_asap_dag()` applies the default to a planned workload | +| `asap_types::ir::apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new())` | Write execution timing into every node from a `PhysicalPropertiesAssignment` (default: all query time) and validate the data-state edges; `PlanOutput::physical_asap_dag()` applies the default to a planned workload | | `asap_types::ir::physical_export::compile_physical_asap_dag(&timed_root)` | Export a timed DAG as a `PhysicalASAPDAG`; rejects an untimed node; `compile_physical_asap_workload(&roots)` exports a batch with one root per query; `.validate()` checks it explicitly | | `PhysicalASAPDAG::materialized_views()` and `.raw_data_retention()` (`asap_types::ir::materialized_view`) | What a runtime keeps for an installed DAG, derived from the DAG and the `retention_ms` installation sets: each materialized view (refresh mode, coverage, inputs, the node's `retention_ms`) and how far back each raw-data source is kept for query-time scans (each query-time `Scan`'s `retention_ms`) | diff --git a/docs/develop_docs/physical-compile-coverage.md b/docs/develop_docs/physical-compile-coverage.md index 9d68caec1..a0b221ddf 100644 --- a/docs/develop_docs/physical-compile-coverage.md +++ b/docs/develop_docs/physical-compile-coverage.md @@ -5,7 +5,7 @@ Audience: developers moving computation from ASAPQuery-backend into ## Contract -Logical selection decides what to compute. A `MaterializationAssignment` sets +Logical selection decides what to compute. A `PhysicalPropertiesAssignment` sets node timing (Stage 2 materialization chooses it per physical candidate). `physical_planner::compile` turns a timed `PhysicalASAPDAG` into physical operator DAGs. The backend owns ingestion, tumbling windows, storage, stored-state evaluation, external exact engines, pricing/selection, and execution scheduling. diff --git a/docs/develop_docs/pre-asap-ir.md b/docs/develop_docs/pre-asap-ir.md index fb93b8ae9..e49f86c63 100644 --- a/docs/develop_docs/pre-asap-ir.md +++ b/docs/develop_docs/pre-asap-ir.md @@ -33,7 +33,7 @@ pub struct OperatorNode { pub result_kind: OperatorResultKind, // Relation | InstantVector | RangeVector | State | Scalar pub schema: Schema, // output schema, derived at construction pub guarantee: Option, // None until accuracy assessment establishes one - pub timing: Option, // None until a materialization assignment is applied + pub timing: Option, // None until a physical properties assignment is applied pub lifetime: Lifetime, // None until Stage 2 keeps the node's output } ``` @@ -48,10 +48,10 @@ pub struct OperatorNode { retain a more specific schema through `OperatorNode::with_schema`. - `guarantee` is `None` until accuracy assessment establishes one; `None` never means exact. - `timing` is `None` in every front-end DAG and every candidate. It is written by - `ir::timing::apply_materialization_timings` (see the Post-ASAP IR document); export rejects an + `ir::timing::apply_physical_properties` (see the Post-ASAP IR document); export rejects an untimed node. - `lifetime` is `Lifetime::None` in every front-end DAG. Stage 2 writes it, with - `timing`, through `ir::timing::apply_materialization_timings` from its materialization + `timing`, through `ir::timing::apply_physical_properties` from its materialization assignment; together they are the node's `PhysicalProperties`. `OperatorNode::children()` returns the operator's inputs in field order followed by the diff --git a/docs/develop_docs/target-candidate-api-migration.md b/docs/develop_docs/target-candidate-api-migration.md index 77cc5379d..7d89d4389 100644 --- a/docs/develop_docs/target-candidate-api-migration.md +++ b/docs/develop_docs/target-candidate-api-migration.md @@ -47,7 +47,7 @@ or `Operator::ASAP(ASAPOp)`. Old public names are not kept as aliases. | `SummaryExpr::ValueOperation { .. }` over an evaluation | An ordinary `NonASAPOp` (`Project`, `Filter`, `Sort`, `Limit`, `Aggregate`) reading an ASAP node; `FinalizeExactAccumulator`, `MaintainPopulation`, `EvaluatePopulation` are `ASAPOp` variants | | `Replacement::Summary(..)` / `Replacement::Rewrite(..)` | `Replacement::SubDAG(Rc)`; `is_logical_rewrite` tells them apart | | `SummaryFamilyType` | `FieldDataType` (its non-`Plain` variants) | -| Timing stored on post-ASAP nodes | `OperatorNode::timing`, `None` until `ir::timing::apply_materialization_timings` writes it from a `MaterializationAssignment` (default: all query time) | +| Timing stored on post-ASAP nodes | `OperatorNode::timing`, `None` until `ir::timing::apply_physical_properties` writes it from a `PhysicalPropertiesAssignment` (default: all query time) | | `UnresolvedQueryExpr` + `asap_types::pre_asap::resolve_root` | `UnresolvedOp` / `UnresolvedScalar` + `asap_frontend_common::resolve_root` | | `pre_asap::canonicalize`, `pre_asap::cse::share_common_sub_dags` | `asap_frontend_common` `canonicalize` (crate-private), `share_common_sub_dags` (crate-private in `asap_logical_asap_optimization`, `stage0/cse.rs`) | | `asap_types::post_asap::compile_post_asap_dag` (wire version 5, `Fallback`/`Binary`/`Value` payloads) | `asap_types::ir::physical_export::compile_physical_asap_dag` (`PhysicalASAPDAG`, carried in the plan file versioned by `asap_planner::INSTALLABLE_PLAN_WIRE_VERSION`: one node per operator, `Operator` payloads, `ScalarRef` edges); input must be timed | diff --git a/docs/develop_docs/tumbling-window-search-compression-evaluation.md b/docs/develop_docs/tumbling-window-search-compression-evaluation.md index 2419cf97e..de049ba47 100644 --- a/docs/develop_docs/tumbling-window-search-compression-evaluation.md +++ b/docs/develop_docs/tumbling-window-search-compression-evaluation.md @@ -110,7 +110,7 @@ The nine viewer workloads also passed **9/9**, with **40/40** query requirements ### Final regression follow-up -The regression suite found a genuine optimization regression outside window planning. Two identical SQL percentiles over an at-rest table were sent through progressive tumbling window rounds solely because they repeat every ten minutes. No computation had a tumbling-window-eligible window, so the rounds rebuilt the same 40-configuration, 150-connection model and restarted refinement. The 128-evaluation budget expired with two identical unmaterialized KLL builds, costing 0.007678692288679677 per second instead of the baseline's one shared query-materialized build at 0.006000017830006526 (+27.98%). The original pointer-sharing assertion failed both in the suite and in isolation; it was retained unchanged. +The regression suite found a genuine optimization regression outside window planning. Two identical SQL percentiles over an at-rest table were sent through progressive tumbling window rounds solely because they repeat every ten minutes. No computation had a tumbling-window-eligible window, so the rounds rebuilt the same 40-configuration, 150-connection model and restarted refinement. The 128-evaluation budget expired with two identical not_kept KLL builds, costing 0.007678692288679677 per second instead of the baseline's one shared query-materialized build at 0.006000017830006526 (+27.98%). The original pointer-sharing assertion failed both in the suite and in isolation; it was retained unchanged. Revision `fe171f64` bypasses tumbling-window-domain expansion when the initial computations contain neither a positive range window nor an existing tumbling-window chain. It searches the complete candidate domain directly; at-rest status alone does not disable tumbling window planning. The same SQL fixture now passes the original sharing test and selects one shared KLL with exactly the baseline cost. Its report records 58 evaluations, `optimal`, one `Complete` round, and no pending widths. This fix avoids repeated identical-domain searches rather than increasing the budget or relaxing correctness checks. From a46f71559b11084d46b8154797dfef710862bd11 Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 00:59:50 +0000 Subject: [PATCH 4/9] refactor: review fixes: one encoding of not kept, no duplicated accessors - PhysicalPropertiesAssignment maps kept nodes only: with_default and its unassigned field are deleted (tests use kept_at_ingestion_where_allowed), set takes PhysicalProperties, get is private, copy_assignment replaces split_by_timing's get/set pair; Stage 2's choice callback returns an option index instead of Option>. - PhysicalASAPDAGValidationError::InvalidPhysicalProperties carries the typed reason; UnkeptSummaryBuildNotAtQueryTime is its own variant. - Lifetime::is_across_evaluations, OperatorNode::physical_properties and PhysicalASAPDAGNode::physical_properties replace hand-written matches, is_view and kept_at_ingestion. - PhysicalWorkloadPlan::lifetime (a copy of dag's lifetimes) is deleted. - PhysicalProperties gets named consts for the values Stage 2 builds; the Stage 2 constructors and test copies are deleted, as is optimize_physical_asap_assigned (duplicate of the test_support entry). - Code says kept, not materialized, for lifetime != None. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/src/execution_demand.rs | 46 +-- crates/cost/src/usage.rs | 4 +- crates/cost/tests/held_memory.rs | 10 +- crates/cost/tests/ingestion_refresh_runs.rs | 26 +- crates/devtools/src/candidate_labels.rs | 28 +- crates/devtools/tests/asap_planner.rs | 36 +- crates/executor/src/physical_planner/mod.rs | 3 +- .../executor/tests/precompute_candidates.rs | 2 +- .../executor/tests/weighted_topk_binding.rs | 9 +- crates/integration-tests/src/lib.rs | 12 +- .../tests/materialized_views.rs | 26 +- .../tests/physical_common/mod.rs | 10 +- .../tests/physical_properties_e2e.rs | 32 +- .../tests/planner_layering_common/mod.rs | 14 +- .../tests/planner_layering_example1.rs | 14 +- .../tests/planner_layering_example4.rs | 18 +- .../tests/production_rollup_workloads.rs | 2 +- crates/integration-tests/tests/reuse_rules.rs | 7 +- .../tests/rollup_controlled.rs | 23 +- .../tests/runtime_handoff.rs | 8 +- .../tests/tumbling_window_merge.rs | 12 +- .../src/pass1/per_computation_candidates.rs | 3 +- .../src/test_support.rs | 10 +- .../src/catalog/configurations.rs | 27 +- .../src/catalog/realize.rs | 41 ++- crates/physical-asap-optimization/src/lib.rs | 153 +++------ .../src/split_by_timing.rs | 46 ++- crates/plan-selection/src/groups.rs | 11 +- crates/plan-selection/src/groups/tests.rs | 12 +- crates/plan-selection/src/lib.rs | 49 ++- crates/planner/src/installable.rs | 16 +- .../tests/deployment_accuracy_model.rs | 2 +- crates/planner/tests/per_sample_updater.rs | 2 +- crates/planner/tests/runtime_install.rs | 28 +- crates/planner/tests/summary_sharing.rs | 4 +- crates/types/src/ir/materialized_view.rs | 11 +- crates/types/src/ir/operator/node.rs | 8 +- crates/types/src/ir/physical_export.rs | 51 +-- crates/types/src/ir/properties/timing.rs | 323 +++++++++--------- crates/types/src/physical/properties.rs | 54 ++- crates/types/src/physical/workload_plan.rs | 21 +- crates/types/tests/materialized_view.rs | 45 +-- crates/types/tests/physical_export.rs | 29 +- crates/types/tests/schema_rebuilding.rs | 2 +- crates/types/tests/summary_merge_structure.rs | 8 +- crates/types/tests/tumbling_window_chain.rs | 9 +- docs/design_docs/concepts/post-asap-ir.md | 16 +- .../physical-planning-and-deployment.md | 2 +- .../planner-layering-example4-acceptance.md | 4 +- 49 files changed, 587 insertions(+), 742 deletions(-) diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index f2343a1cd..9c12d997e 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -10,7 +10,7 @@ use super::analytical::AnalyticalCostError; use asap_types::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; use asap_types::ir::properties::ExecutionTiming; -use asap_types::physical::Lifetime; +use asap_types::physical::PhysicalProperties; use asap_types::workload::{QueryRecurrence, RangeEvaluation, RepeatedDemand}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; @@ -287,8 +287,8 @@ pub fn query_starts(dag: &PhysicalASAPDAG) -> Vec> { pub enum Consumer { /// Query `.0` (an operator or scalar root), at its own rate. Query(usize), - /// A materialized node, at that node's rate. - Materialized(PhysicalASAPNodeId), + /// A kept node, at that node's rate. + Kept(PhysicalASAPNodeId), } /// The consumers of each not-kept node of `dag` that any consumer @@ -297,13 +297,13 @@ pub enum Consumer { /// each once; the queries first, in order, then the materialized nodes in /// `dag`'s node order. pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap> { - let materialized: Vec = dag + let kept_nodes: Vec = dag .nodes .iter() .filter(|n| n.lifetime.is_kept()) .map(|n| n.id) .collect(); - let is_materialized: HashSet = materialized.iter().copied().collect(); + let is_kept: HashSet = kept_nodes.iter().copied().collect(); let inputs = |id: PhysicalASAPNodeId| { dag.edges .iter() @@ -315,16 +315,16 @@ pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap> = HashMap::new(); for (consumer, start) in walks { let mut seen = HashSet::new(); let mut stack: Vec = start; while let Some(id) = stack.pop() { - if is_materialized.contains(&id) || !seen.insert(id) { + if is_kept.contains(&id) || !seen.insert(id) { continue; } consumers.entry(id).or_default().push(consumer); @@ -359,11 +359,15 @@ pub fn computations( root_rates: Option<&[f64]>, ) -> Result, AnalyticalCostError> { let range_of = |query: usize| range_evaluations.get(query).copied().flatten(); - let materialized: HashMap<_, _> = dag + let kept_nodes: HashMap = dag .nodes .iter() - .filter(|n| n.lifetime.is_kept()) - .map(|n| (n.id, (n.output_state.timing, n.lifetime))) + .filter_map(|n| { + n.physical_properties() + .ok() + .filter(|p| p.lifetime().is_kept()) + .map(|p| (n.id, p)) + }) .collect(); let inputs = |id: PhysicalASAPNodeId| { dag.edges @@ -385,11 +389,11 @@ pub fn computations( stack.extend(inputs(id)); } } - let mut rate_of_materialized = HashMap::new(); - for (&id, &(timing, lifetime)) in &materialized { - let at_ingestion = timing == ExecutionTiming::IngestionTime; + let mut rate_of_kept = HashMap::new(); + for (&id, &properties) in &kept_nodes { + let at_ingestion = properties.timing() == ExecutionTiming::IngestionTime; // A query-time chain kept across evaluations is built once per request. - let per_request = !at_ingestion && matches!(lifetime, Lifetime::AcrossEvaluations(_)); + let per_request = !at_ingestion && properties.lifetime().is_across_evaluations(); let rate = match at_ingestion { true => 1.0, _ => evaluation_rate( @@ -400,7 +404,7 @@ pub fn computations( non_repeating_query_horizon_seconds, )?, }; - rate_of_materialized.insert(id, rate); + rate_of_kept.insert(id, rate); } // Each query consumer's rate. let mut query_rates = Vec::new(); @@ -415,9 +419,9 @@ pub fn computations( } // The refresh window of each node refreshed at ingestion. let refresh_windows = dag.refresh_windows( - materialized + kept_nodes .iter() - .filter(|(_, (timing, _))| *timing == ExecutionTiming::IngestionTime) + .filter(|(_, properties)| properties.timing() == ExecutionTiming::IngestionTime) .map(|(&id, _)| id), ); let mut count: HashMap<_, (u64, f64)> = HashMap::new(); @@ -426,7 +430,7 @@ pub fn computations( // The refresh windows whose ingestion run already computes the node. let mut runs = HashSet::new(); for consumer in of_node { - if let Consumer::Materialized(node) = consumer { + if let Consumer::Kept(node) = consumer { if let Some(Some(window)) = refresh_windows.get(&node) { if !runs.insert(*window) { continue; @@ -436,7 +440,7 @@ pub fn computations( entry.0 += 1; entry.1 += match consumer { Consumer::Query(query) => query_rates[query], - Consumer::Materialized(node) => rate_of_materialized[&node], + Consumer::Kept(node) => rate_of_kept[&node], }; } } @@ -444,7 +448,7 @@ pub fn computations( .nodes .iter() .map(|n| { - let times = match rate_of_materialized.get(&n.id) { + let times = match rate_of_kept.get(&n.id) { Some(&rate) => (1, rate), None => count.get(&n.id).copied().unwrap_or((0, 0.0)), }; diff --git a/crates/cost/src/usage.rs b/crates/cost/src/usage.rs index e14c672ab..a74d2ddf1 100644 --- a/crates/cost/src/usage.rs +++ b/crates/cost/src/usage.rs @@ -282,9 +282,7 @@ pub fn plan_cost( .map_err(|error| (id, error))?; rate * latency.get(query).map_or(0.0, QueryLatency::total_ms) } - Consumer::Materialized(node) => { - multipliers[&node].1 * longest_reader_ms(node) - } + Consumer::Kept(node) => multipliers[&node].1 * longest_reader_ms(node), }; } sum diff --git a/crates/cost/tests/held_memory.rs b/crates/cost/tests/held_memory.rs index c4faee50c..ac1954509 100644 --- a/crates/cost/tests/held_memory.rs +++ b/crates/cost/tests/held_memory.rs @@ -100,7 +100,7 @@ fn close(a: f64, b: f64) -> bool { /// `bytes · rate · latency_0`, not the rate-weighted mean of the two /// latencies. #[test] -fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { +fn working_memory_read_by_a_kept_node_is_held_for_the_longest_reader() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let plans = optimize_physical_asap( @@ -129,10 +129,10 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { let [outer_ms, inner_ms] = latency_ms(recomputed); assert!(outer_ms > inner_ms, "{outer_ms} vs {inner_ms}"); let below = |dag: &PhysicalASAPDAG| { - let materialized = dag.roots[1]; + let kept_node = dag.roots[1]; held_memory_costs(dag) .into_iter() - .filter(move |(id, _, _)| *id != materialized && *id != dag.roots[0]) + .filter(move |(id, _, _)| *id != kept_node && *id != dag.roots[0]) .collect::>() }; let checked = below(recomputed); @@ -144,7 +144,7 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { // Below a `OneEvaluation` node: the longest reader's latency at the // materialized node's rate (its readers' schedules together). - let materialized_rate = evaluation_rate( + let kept_rate = evaluation_rate( recurrence().iter().map(|r| (r, None)), CostInputs::default().non_repeating_query_horizon_seconds, ) @@ -155,7 +155,7 @@ fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { assert!(!checked.is_empty(), "the nodes below it hold memory"); for (id, bytes, term) in checked { assert_eq!(lifetime_of(shared, id), Lifetime::None); - let expected = bytes * materialized_rate * outer_ms / 1_000.0; + let expected = bytes * kept_rate * outer_ms / 1_000.0; assert!(close(term, expected), "node {id}: {term} vs {expected}"); } } diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index 6931a6f3f..182e5effd 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -9,7 +9,6 @@ use std::time::Duration; use asap_cost::execution_demand::computations; use asap_types::ir::operator::operator_properties::{Reduction, Source, TimeShift}; use asap_types::ir::physical_export::{compile_physical_asap_workload, PhysicalASAPDAG}; -use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::{ DataType, Field, FieldDataType, GroupingStrategy, Schema, SketchAlgorithm, SketchKind, @@ -19,7 +18,7 @@ use asap_types::ir::{ apply_physical_properties_to_roots, ASAPOp, NonASAPOp, Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, TimeRangeKind, }; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; +use asap_types::physical::PhysicalProperties; use asap_types::workload::{QueryRecurrence, RepeatedDemand, RepetitionInterval}; /// `m` with columns `ts`, `value` and `job`. @@ -81,7 +80,7 @@ fn dag_of(summaries: &[Rc], kept: Option) -> P let roots: Vec = summaries .iter() .map(|summary| { - if kept.is_some() { + if let Some(kept) = kept { assignment.set(summary, kept); } QueryRoot::Operator( @@ -133,15 +132,6 @@ fn shifted(child: &Rc, offset_ms: i64) -> Rc { .unwrap() } -/// Kept at ingestion time until a query reads it. -fn at_ingestion() -> Option { - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok() -} - /// A KLL chain and a DDSketch chain of 10 s tumbling windows over one `Scan`, both /// kept at ingestion, are refreshed in one ingestion run per tumbling window: the /// `Scan` is computed once per second of arriving data, not twice. @@ -153,7 +143,7 @@ fn a_scan_under_two_chains_of_one_tumbling_window_width_is_computed_once() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (1, 1.0)); } @@ -169,7 +159,7 @@ fn a_scan_under_chains_of_two_tumbling_window_widths_is_computed_for_each() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 60_000, 5), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -219,7 +209,7 @@ fn a_scan_under_chains_of_10_10_and_60_s_is_computed_for_each_width() { chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), chain(&scan, SketchAlgorithm::Kll, 60_000, 5), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -239,7 +229,7 @@ fn chains_of_one_width_and_two_phases_are_computed_apart() { 30, ), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -254,7 +244,7 @@ fn nodes_below_a_shared_intermediate_node_are_computed_once_per_run() { chain(&shift, SketchAlgorithm::Kll, 10_000, 6), chain(&shift, SketchAlgorithm::DDSketch, 10_000, 30), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (1, 1.0)); assert_eq!( @@ -288,7 +278,7 @@ fn consumers_of_unbounded_windows_count_alone() { build(SketchAlgorithm::Kll), build(SketchAlgorithm::DDSketch), ], - at_ingestion(), + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!( computations_of(&dag, |op| matches!(op, NonASAPOp::Values { .. })), diff --git a/crates/devtools/src/candidate_labels.rs b/crates/devtools/src/candidate_labels.rs index 585345955..3939d26ed 100644 --- a/crates/devtools/src/candidate_labels.rs +++ b/crates/devtools/src/candidate_labels.rs @@ -145,14 +145,9 @@ fn duration_name(ms: u64) -> String { /// just `logical` when nothing is. pub fn physical_label(logical: &str, candidate: &PhysicalWorkloadPlan) -> String { let mut parts: Vec<(&str, Vec)> = Vec::new(); - for (id, lifetime) in &candidate.lifetime { - let node = candidate - .dag - .nodes - .iter() - .find(|n| n.id == *id) - .expect("an assigned node is in the DAG"); - let phase = match (node.output_state.timing, lifetime) { + for node in &candidate.dag.nodes { + let id = &node.id; + let phase = match (node.output_state.timing, node.lifetime) { (_, Lifetime::None) => continue, (ExecutionTiming::IngestionTime, _) => "ingestion time", (ExecutionTiming::QueryTime, Lifetime::OneEvaluation(_)) => "query time, shared", @@ -496,19 +491,14 @@ mod tests { let one_chain_at_ingestion: Vec = plans .iter() .filter(|plan| { - plan.lifetime + plan.dag + .nodes .iter() - .filter(|(id, lifetime)| { - let node = plan.dag.nodes.iter().find(|n| n.id == **id).unwrap(); - lifetime.is_kept() - && node.output_state.timing == ExecutionTiming::IngestionTime + .filter(|node| { + node.output_state.timing == ExecutionTiming::IngestionTime + && node.lifetime.is_kept() && matches!( - plan.dag - .nodes - .iter() - .find(|n| n.id == **id) - .unwrap() - .payload, + node.payload, Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) ) }) diff --git a/crates/devtools/tests/asap_planner.rs b/crates/devtools/tests/asap_planner.rs index 3feeb906f..8ea70745e 100644 --- a/crates/devtools/tests/asap_planner.rs +++ b/crates/devtools/tests/asap_planner.rs @@ -1579,8 +1579,7 @@ fn scans_projecting_different_labels_are_shared() { let data = workload.data_workload.as_ref().unwrap(); let roots = lower_promql_roots(&workload).unwrap(); use asap_logical_asap_optimization::test_support::with_union_scan_labels; - use asap_types::ir::properties::ExecutionTiming; - use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; + use asap_types::physical::PhysicalProperties; // Plans `roots` with identical sub-DAGs made one node, as the memo's // groups are, and a node read by several roots kept for the evaluation. let plan = |name: &str, roots: &[QueryRoot]| { @@ -1597,24 +1596,21 @@ fn scans_projecting_different_labels_are_shared() { .into_iter() .map(|(_, node)| QueryRoot::Operator(node)) .collect(); - let physical = asap_physical_asap_optimization::optimize_physical_asap_assigned( - name, - &shared, - &entries, - data, - false, - &mut |readers| { - Some((readers.len() > 1).then(|| { - PhysicalProperties::new( - ExecutionTiming::QueryTime, - Lifetime::OneEvaluation(Medium::Memory), - ) - .unwrap() - })) - }, - ) - .unwrap() - .expect("a node read by several roots can be kept for the evaluation"); + let physical = + asap_physical_asap_optimization::test_support::optimize_physical_asap_chosen( + name, + &shared, + &entries, + data, + false, + &mut |_, readers, options| { + let kept = (readers.len() > 1) + .then_some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); + options.iter().position(|option| *option == kept) + }, + ) + .unwrap() + .expect("a node read by several roots can be kept for the evaluation"); let offered = asap_devtools::memo_pricing::reference_select( std::slice::from_ref(&physical), &entries, diff --git a/crates/executor/src/physical_planner/mod.rs b/crates/executor/src/physical_planner/mod.rs index aa2d7f83d..744a42127 100644 --- a/crates/executor/src/physical_planner/mod.rs +++ b/crates/executor/src/physical_planner/mod.rs @@ -1742,8 +1742,7 @@ pub mod test_support { .nodes .iter() .filter(|node| { - nodes.contains(&(node.id as NodeId)) - && !matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) + nodes.contains(&(node.id as NodeId)) && !node.lifetime.is_across_evaluations() }) .map(|node| node.id as NodeId) .collect(); diff --git a/crates/executor/tests/precompute_candidates.rs b/crates/executor/tests/precompute_candidates.rs index b540f8110..5187450f6 100644 --- a/crates/executor/tests/precompute_candidates.rs +++ b/crates/executor/tests/precompute_candidates.rs @@ -113,7 +113,7 @@ fn answer( /// Rate state. Moving Sum before Rate would answer differently across /// counter resets. #[test] -fn grouped_rate_can_be_materialized_before_or_after_grouped_sum() { +fn grouped_rate_can_be_kept_before_or_after_grouped_sum() { let dag = grouped_rate(); let state = dag .nodes diff --git a/crates/executor/tests/weighted_topk_binding.rs b/crates/executor/tests/weighted_topk_binding.rs index 9208ea6da..d02dd2197 100644 --- a/crates/executor/tests/weighted_topk_binding.rs +++ b/crates/executor/tests/weighted_topk_binding.rs @@ -273,12 +273,11 @@ fn rate_updates_cannot_enter_integer_heap_factory() { /// its finalize boundary to query time, which would put the summaries above /// it upstream of a query-time node, so the pin is lifted first. fn continuously_maintained_dag(candidate: &Rc) -> PhysicalASAPDAG { - use planner_types::ir::properties::ExecutionTiming; use planner_types::ir::{ apply_physical_properties, NodeToTimedNodeCache, Operator as IrOperator, OperatorNode, PhysicalPropertiesAssignment, }; - use planner_types::physical::{Lifetime, Medium, PhysicalProperties}; + use planner_types::physical::PhysicalProperties; fn unpinned(node: &Rc) -> Rc { let mut copy = (**node).clone(); copy.operator = node.operator.map_children(unpinned); @@ -296,11 +295,7 @@ fn continuously_maintained_dag(candidate: &Rc) if matches!(node.operator, IrOperator::ASAP(ASAPOp::SummaryAgg { .. })) { assignment.set( &node, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } } diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs index 84b2c974b..0230c2f61 100644 --- a/crates/integration-tests/src/lib.rs +++ b/crates/integration-tests/src/lib.rs @@ -98,11 +98,9 @@ pub mod fixtures { /// Timing and physical ASAP DAG export helpers for planned candidates. pub mod physical_export { use asap_types::ir::physical_export::{compile_physical_asap_dag, PhysicalASAPDAG}; - use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ apply_physical_properties, NodeToTimedNodeCache, OperatorNode, PhysicalPropertiesAssignment, }; - use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; /// Time `root` under the default assignment (no sub-DAG kept, so every @@ -116,13 +114,9 @@ pub mod physical_export { pub fn at_ingestion(root: &Rc) -> Rc { timed_with( root, - &PhysicalPropertiesAssignment::with_default( - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), - ), + &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( + root, + )), ) } diff --git a/crates/integration-tests/tests/materialized_views.rs b/crates/integration-tests/tests/materialized_views.rs index 10aa58ca9..9ca195497 100644 --- a/crates/integration-tests/tests/materialized_views.rs +++ b/crates/integration-tests/tests/materialized_views.rs @@ -12,8 +12,7 @@ use asap_planner::{ use asap_types::ir::operator::Source; use asap_types::ir::physical_export::{compile_physical_asap_workload, PhysicalASAPDAG}; use asap_types::ir::properties::ExecutionTiming; -use asap_types::ir::{ASAPOp, NonASAPOp, Operator}; -use asap_types::physical::Lifetime; +use asap_types::ir::{NonASAPOp, Operator}; use asap_types::workload::PlanningWorkload; use serde_json::Value; @@ -49,21 +48,7 @@ fn repeating_with(queries: &[&str], extra: &str) -> PlanningWorkload { /// evaluations reading its newest tumbling window, as `asap-plan-selection` prices /// it, the longest per source. fn stage3_raw_lookback_ms(dag: &PhysicalASAPDAG) -> Vec<(Source, Option)> { - let kept_chains: HashSet<_> = dag - .nodes - .iter() - .filter(|node| { - matches!( - (&node.payload, node.output_state.timing, node.lifetime), - ( - Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), - ExecutionTiming::QueryTime, - Lifetime::AcrossEvaluations(_) - ) - ) - }) - .map(|node| node.id) - .collect(); + let kept_chains = asap_cost::kept_tumbling_window_chains(dag); let mut lookback: Vec<(Source, Option)> = Vec::new(); for node in &dag.nodes { let Operator::NonASAP(NonASAPOp::Scan { source, .. }) = &node.payload else { @@ -148,9 +133,10 @@ fn a_range_evaluated_query_time_scan_keeps_its_window_plus_the_span() { } /// A plan file of wire version 10 (assembled from the parts of a plan -/// written on `main` before #970: the versioned DAG envelope, `queries`, -/// `stored_outputs`, `query_time_raw_windows`, `selection`) is refused for -/// its version, not for a missing field; a file of this version reads back. +/// written before #970: the versioned DAG envelope, `queries`, +/// `stored_outputs`, `query_time_raw_windows`, `selection`; its DAG nodes +/// carry today's node fields, e.g. `lifetime`) is refused for its version, +/// not for a missing field; its DAG with today's version reads back. #[test] fn a_plan_file_of_an_older_wire_version_is_refused_by_version() { let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/integration-tests/tests/physical_common/mod.rs b/crates/integration-tests/tests/physical_common/mod.rs index d6be3ab28..4b1970380 100644 --- a/crates/integration-tests/tests/physical_common/mod.rs +++ b/crates/integration-tests/tests/physical_common/mod.rs @@ -51,14 +51,8 @@ pub fn compile_at_ingestion_physical_asap_dag( ) -> Result> { compile_with( root, - &asap_types::ir::PhysicalPropertiesAssignment::with_default( - asap_types::physical::PhysicalProperties::new( - asap_types::ir::properties::ExecutionTiming::IngestionTime, - asap_types::physical::Lifetime::AcrossEvaluations( - asap_types::physical::Medium::Memory, - ), - ) - .ok(), + &asap_types::ir::PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed( + std::slice::from_ref(root), ), ) } diff --git a/crates/integration-tests/tests/physical_properties_e2e.rs b/crates/integration-tests/tests/physical_properties_e2e.rs index 838712175..b0d323ed3 100644 --- a/crates/integration-tests/tests/physical_properties_e2e.rs +++ b/crates/integration-tests/tests/physical_properties_e2e.rs @@ -26,15 +26,6 @@ use asap_types::ir::{ }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; -/// Kept at ingestion time until a query reads it. -fn at_ingestion() -> Option { - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok() -} - use crate::physical_common; /// The logical DAG the planner pipeline selects for `query`, optionally with @@ -82,12 +73,12 @@ fn sketch_candidate(query: &str) -> Rc { .expect("a sketch candidate") } -/// The two placements under test: nothing stored, and every state stored at -/// ingestion time where the DAG allows it. -fn placements() -> [PhysicalPropertiesAssignment; 2] { +/// The two placements of `root` under test: nothing stored, and every state +/// stored at ingestion time where the DAG allows it. +fn placements(root: &Rc) -> [PhysicalPropertiesAssignment; 2] { [ PhysicalPropertiesAssignment::default(), - PhysicalPropertiesAssignment::with_default(at_ingestion()), + PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)), ] } @@ -217,7 +208,7 @@ fn values_1_to_100(schema: &SchemaRef, _metric: &str) -> Batch { fn physical_properties_decide_precompute_contents() { let root = sketch_candidate("quantile(0.99, latency)"); let mut answers = Vec::new(); - for assignment in placements() { + for assignment in placements(&root) { let dag = timed_dag(&root, &assignment); let ingestion = Scope::Ingestion { window_start_ms: 0, @@ -228,7 +219,7 @@ fn physical_properties_decide_precompute_contents() { answers.push(values); } assert_eq!(answers[1].len(), 1); - assert!(!states(&timed_dag(&root, &placements()[1])).is_empty()); + assert!(!states(&timed_dag(&root, &placements(&root)[1])).is_empty()); assert_eq!(answers[0], answers[1]); } @@ -264,7 +255,10 @@ fn mixed_placement_answers_like_query_time() { "two explicitly selected KLL builds" ); let mut mixed = PhysicalPropertiesAssignment::default(); - mixed.set(&sketches(&root)[0], at_ingestion()); + mixed.set( + &sketches(&root)[0], + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let mut answers = Vec::new(); for assignment in [PhysicalPropertiesAssignment::default(), mixed] { let dag = timed_dag(&root, &assignment); @@ -322,7 +316,7 @@ fn arithmetic_over_different_selectors_matches_prometheus() { ("m", "b", 250, 5.0), ("n", "a", 250, 7.0), ]; - for assignment in placements() { + for assignment in placements(&root) { let dag = timed_dag(&root, &assignment); assert!(!ingestion_binary(&dag)); let (values, _) = execute(&dag, &job_samples(&disjoint), INGESTION_WINDOW, 300_000); @@ -334,7 +328,7 @@ fn arithmetic_over_different_selectors_matches_prometheus() { "quantile(0.9, sum_over_time(m[1m]) + sum_over_time(n[1m]))", true, ); - assert!(!ingestion_binary(&timed_dag(&root, &placements()[1]))); + assert!(!ingestion_binary(&timed_dag(&root, &placements(&root)[1]))); } /// Arithmetic over one selector is aligned maintenance when stored at @@ -352,7 +346,7 @@ fn arithmetic_over_one_selector_executes() { ("m", "a", 290, 2.0), ("m", "b", 250, 5.0), ]; - let [not_kept, at_ingestion] = placements().map(|a| timed_dag(&root, &a)); + let [not_kept, at_ingestion] = placements(&root).map(|a| timed_dag(&root, &a)); assert!(!ingestion_binary(¬_kept)); assert!( ingestion_binary(&at_ingestion), diff --git a/crates/integration-tests/tests/planner_layering_common/mod.rs b/crates/integration-tests/tests/planner_layering_common/mod.rs index 0c5005657..8330db726 100644 --- a/crates/integration-tests/tests/planner_layering_common/mod.rs +++ b/crates/integration-tests/tests/planner_layering_common/mod.rs @@ -675,7 +675,7 @@ pub fn assert_one_not_kept_physical_candidate_per_logical(run: &Run) { let base = p.id.split("-m").next().unwrap(); assert_eq!(&base[1..], &p.from_logical[1..], "{}", p.id); let not_kept = !p.id.contains("-m"); - assert_eq!(not_kept, !p.candidate.materializes_any(), "{}", p.id); + assert_eq!(not_kept, !p.candidate.keeps_any(), "{}", p.id); if not_kept { for n in &p.dag().nodes { assert_eq!(keeping(p, n.id), Keeping::NotKept); @@ -689,9 +689,7 @@ pub fn assert_one_not_kept_physical_candidate_per_logical(run: &Run) { /// The physical candidates with nothing materialized, one per logical /// candidate. pub fn not_kept(run: &Run) -> impl Iterator { - run.physical - .iter() - .filter(|p| !p.candidate.materializes_any()) + run.physical.iter().filter(|p| !p.candidate.keeps_any()) } /// One selected id; every other candidate rejected once, with a reason. @@ -772,7 +770,7 @@ pub fn assert_each_node_charged_per_consuming_query(run: &Run) { /// nodes and counts each node once. The consumers kept at ingestion time of one /// refresh window share one ingestion run and count once (#1151). pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { - let materialized: BTreeSet<_> = dag + let kept_nodes: BTreeSet<_> = dag .nodes .iter() .filter(|n| n.lifetime.is_kept()) @@ -789,7 +787,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { .iter() .map(|(_, expr)| (expr.operator_refs().into_iter().copied().collect(), None)), ) - .chain(materialized.iter().map(|&id| { + .chain(kept_nodes.iter().map(|&id| { let at_ingestion = dag .nodes .iter() @@ -804,7 +802,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { let mut times: BTreeMap<_, _> = dag .nodes .iter() - .map(|n| (n.id, u64::from(materialized.contains(&n.id)))) + .map(|n| (n.id, u64::from(kept_nodes.contains(&n.id)))) .collect(); // The (node, refresh window) pairs whose ingestion run is counted. let mut runs = HashSet::new(); @@ -812,7 +810,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { let mut seen = HashSet::new(); let mut stack = start; while let Some(id) = stack.pop() { - if materialized.contains(&id) || !seen.insert(id) { + if kept_nodes.contains(&id) || !seen.insert(id) { continue; } if window.is_none_or(|window| runs.insert((id, window))) { diff --git a/crates/integration-tests/tests/planner_layering_example1.rs b/crates/integration-tests/tests/planner_layering_example1.rs index be2d8ac45..6838e4bca 100644 --- a/crates/integration-tests/tests/planner_layering_example1.rs +++ b/crates/integration-tests/tests/planner_layering_example1.rs @@ -460,7 +460,7 @@ fn stage2_physical_asap_optimization_preserves_logical_choices() { let (option, shared) = classify(p.dag(), &p.query_roots); let (logical_option, logical_shared) = classify(&source.dag, &source.query_roots); assert_eq!(option, logical_option, "{} vs {}", p.id, source.id); - if !p.candidate.materializes_any() { + if !p.candidate.keeps_any() { assert_eq!(shared, logical_shared, "{} vs {}", p.id, source.id); } } @@ -568,7 +568,7 @@ fn stage2_physical_asap_optimization_summary_topk_is_build_then_estimate() { /// with every chain at query time, since a chain maintained at ingestion /// time leaves one query reading the input at query time. #[test] -fn stage2_physical_asap_optimization_materializes_only_tumbling_windows_at_ingestion() { +fn stage2_physical_asap_optimization_keeps_only_tumbling_windows_at_ingestion() { let run = pipeline(); let mut counter_maintained = 0; let mut shared_once = 0; @@ -829,7 +829,7 @@ fn stage3_plan_selection_charges_each_node_per_consuming_query() { /// two accumulators (rate, sum) and their finalizations twice, once per query; the walks from /// both roots stop at the materialized `time_range`, which is computed once /// and reads the scan once. -fn materialized_case() -> Run { +fn kept_case() -> Run { let mut workload = example1(); let repeating = workload.query_workload.repeating_queries.as_mut().unwrap(); repeating.truncate(1); @@ -871,8 +871,8 @@ fn materialized_case() -> Run { /// The charging helper agrees with plan selection when a node is /// materialized. #[test] -fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_materialized_node() { - let run = materialized_case(); +fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_kept_node() { + let run = kept_case(); let p = &run.physical[0]; let mut by_kind: Vec<_> = run.selection.costs[&p.id] .per_node @@ -898,8 +898,8 @@ fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_materiali /// Charging the scan under a materialized node once per query is caught. #[test] #[should_panic(expected = "multiplier of")] -fn stage3_plan_selection_charging_helper_rejects_recounting_below_a_materialized_node() { - let mut run = materialized_case(); +fn stage3_plan_selection_charging_helper_rejects_recounting_below_a_kept_node() { + let mut run = kept_case(); let p = run.physical[0].clone(); let scan = p .dag() diff --git a/crates/integration-tests/tests/planner_layering_example4.rs b/crates/integration-tests/tests/planner_layering_example4.rs index 52e62dd83..281e6572d 100644 --- a/crates/integration-tests/tests/planner_layering_example4.rs +++ b/crates/integration-tests/tests/planner_layering_example4.rs @@ -157,7 +157,7 @@ fn pattern_a_windows_and_offsets() -> (Vec, Vec) { /// Every materialized output of every candidate of `workload` is kept for at /// least its longest reader's `windows[q] + offsets[q]`. -fn assert_materialized_outputs_cover_their_consumers( +fn assert_kept_outputs_cover_their_consumers( workload: &PlanningWorkload, windows: &[u64], offsets: &[u64], @@ -191,24 +191,24 @@ fn assert_materialized_outputs_cover_their_consumers( /// A materialized output is kept for as long as its consumers read: it covers every reader's lookback and offset. /// The monthly variant runs in -/// `stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers`. +/// `stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers`. #[test] -fn stage2_physical_asap_optimization_materialized_output_covers_its_consumers() { +fn stage2_physical_asap_optimization_kept_output_covers_its_consumers() { let (windows, offsets) = pattern_a_windows_and_offsets(); for workload in [once(), at_rest()] { - assert_materialized_outputs_cover_their_consumers(&workload, &windows, &offsets); + assert_kept_outputs_cover_their_consumers(&workload, &windows, &offsets); } - assert_materialized_outputs_cover_their_consumers(&pattern_b(), &[PATTERN_B_WINDOW_MS], &[0]); + assert_kept_outputs_cover_their_consumers(&pattern_b(), &[PATTERN_B_WINDOW_MS], &[0]); } /// The monthly variant of -/// `stage2_physical_asap_optimization_materialized_output_covers_its_consumers`: +/// `stage2_physical_asap_optimization_kept_output_covers_its_consumers`: /// it plans 67,228 candidates, too slow for a debug build in CI. #[test] #[ignore = "slow: run in release by hand"] -fn stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers() { +fn stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers() { let (windows, offsets) = pattern_a_windows_and_offsets(); - assert_materialized_outputs_cover_their_consumers(&monthly(), &windows, &offsets); + assert_kept_outputs_cover_their_consumers(&monthly(), &windows, &offsets); } // ── Pattern A ──────────────────────────────────────────────────────────── @@ -235,7 +235,7 @@ fn stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option() /// A materialized shared EH is one build node read by all five queries, charged once. #[test] #[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] -fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers() { +fn stage2_physical_asap_optimization_a_kept_eh_is_built_once_for_all_consumers() { let run = run_promql(&once()); for (m, (id, build)) in eh_options(&run) { if m == NotKept { diff --git a/crates/integration-tests/tests/production_rollup_workloads.rs b/crates/integration-tests/tests/production_rollup_workloads.rs index 85c4ddd2f..6209bed94 100644 --- a/crates/integration-tests/tests/production_rollup_workloads.rs +++ b/crates/integration-tests/tests/production_rollup_workloads.rs @@ -262,7 +262,7 @@ fn independent_kll_cost( entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(None), + &mut |_, _, _| Some(0), // option 0: not kept ) .unwrap() .unwrap(); diff --git a/crates/integration-tests/tests/reuse_rules.rs b/crates/integration-tests/tests/reuse_rules.rs index ba041c9ee..c39eda65f 100644 --- a/crates/integration-tests/tests/reuse_rules.rs +++ b/crates/integration-tests/tests/reuse_rules.rs @@ -225,9 +225,10 @@ fn select( .expect("the selected plan"); let name = selected.from_logical.clone(); let built_once = selected - .lifetime - .values() - .any(|lifetime| matches!(lifetime, Lifetime::OneEvaluation(_))); + .dag + .nodes + .iter() + .any(|node| matches!(node.lifetime, Lifetime::OneEvaluation(_))); let roots = plans .iter() .find(|(n, _)| *n == name) diff --git a/crates/integration-tests/tests/rollup_controlled.rs b/crates/integration-tests/tests/rollup_controlled.rs index 2b3bc1ad4..17c94dffb 100644 --- a/crates/integration-tests/tests/rollup_controlled.rs +++ b/crates/integration-tests/tests/rollup_controlled.rs @@ -12,7 +12,6 @@ use asap_types::{ schema::{DataType, Field, Schema, SketchAlgorithm}, ASAPOp, OperatorNode, QueryRoot, }, - physical::PhysicalProperties, workload::PlanningWorkload, }; use std::{collections::HashSet, rc::Rc}; @@ -119,20 +118,18 @@ fn controlled_distinct_rollup_prices_the_original_workload() { &mut |node, _, options| { // Kept for one evaluation where offered, as two // queries reading one build allow. - let shared: Option> = options - .iter() - .find(|kept| { - kept.is_some_and(|p| { - matches!( - p.lifetime(), - asap_types::physical::Lifetime::OneEvaluation(_) - ) - }) + let shared = options.iter().position(|kept| { + kept.is_some_and(|p| { + matches!( + p.lifetime(), + asap_types::physical::Lifetime::OneEvaluation(_) + ) }) - .copied(); + }); + // Option 0: not kept. Some(match shared { - Some(kept) if builds.contains(&node) => kept, - _ => None, + Some(index) if builds.contains(&node) => index, + _ => 0, }) }, ) diff --git a/crates/integration-tests/tests/runtime_handoff.rs b/crates/integration-tests/tests/runtime_handoff.rs index 1197a32b8..b8063e039 100644 --- a/crates/integration-tests/tests/runtime_handoff.rs +++ b/crates/integration-tests/tests/runtime_handoff.rs @@ -61,7 +61,7 @@ async fn plan(workload: &PlanningWorkload, capabilities: &DeploymentCapabilities .expect("Example 4b plans") } -fn materialized_count(dag: &PhysicalASAPDAG) -> usize { +fn kept_count(dag: &PhysicalASAPDAG) -> usize { dag.nodes.iter().filter(|n| n.lifetime.is_kept()).count() } @@ -74,7 +74,7 @@ async fn export_carries_the_selected_lifetime() { let output = plan(&example4b(), &capabilities).await; let dag = output.physical_asap_dag().expect("exports"); assert!( - materialized_count(&dag) > 0, + kept_count(&dag) > 0, "the selected tumbling windows are stored" ); assert!(dag @@ -130,7 +130,7 @@ async fn installable_plan_has_its_tumbling_window_chains_expanded() { let dag = &installed.dag; let views = plan.materialized_views().unwrap(); assert_eq!(tumbling_window_chain_count(dag), 0); - assert_eq!(materialized_count(dag), views.len()); + assert_eq!(kept_count(dag), views.len()); let roots: Vec = dag.roots.iter().map(|&r| r as u64).collect(); let compiled = compile(dag, &views, &roots).expect("the executor compiles it"); assert_eq!(plan.query_texts.len(), 1); @@ -193,7 +193,7 @@ async fn reference_plan_runs_the_installable_plan_at_query_time() { let plan = installable(&example4b()).await; let reference = query_time_reference(&plan).expect("re-times"); reference.validate().unwrap(); - assert_eq!(materialized_count(&reference.dag), 0); + assert_eq!(kept_count(&reference.dag), 0); assert!(reference.materialized_views().unwrap().is_empty()); // The reference reads the raw data the plan's views were refreshed from. let [retention] = reference.raw_data_retention().unwrap().try_into().unwrap(); diff --git a/crates/integration-tests/tests/tumbling_window_merge.rs b/crates/integration-tests/tests/tumbling_window_merge.rs index 2b8f4feaa..3be17cd43 100644 --- a/crates/integration-tests/tests/tumbling_window_merge.rs +++ b/crates/integration-tests/tests/tumbling_window_merge.rs @@ -281,11 +281,7 @@ fn execute_retained( for tumbling_window in tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } execute_retained_as(root, &assignment, samples) @@ -306,11 +302,7 @@ fn execute_maintained_chain( let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &chain, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(planned, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); diff --git a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs index 1e4aa4a82..37b573d33 100644 --- a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs +++ b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs @@ -120,7 +120,6 @@ use asap_types::ir::{ ASAPOp, BinaryOperator, ExprSemantics, NonASAPOp, Operator, OperatorNode, OperatorResultKind, Predicate, ProjectItem, QueryRoot, ScalarExpr, SchemaDerivationError, }; -use asap_types::physical::Lifetime; use thiserror::Error; use asap_accuracy::composition::parse_raw_data_samples_sign_statistic; @@ -835,7 +834,7 @@ pub fn generate_per_computation_candidates( if !seen.insert(Rc::as_ptr(&node)) { continue; } - if node.timing.is_some() || node.lifetime != Lifetime::None { + if node.timing.is_some() || node.lifetime.is_kept() { return Err(PerComputationCandidateError::AssignedPhysicalAnnotation); } for child in node.children() { diff --git a/crates/logical-asap-optimization/src/test_support.rs b/crates/logical-asap-optimization/src/test_support.rs index 356622a69..306a7edc2 100644 --- a/crates/logical-asap-optimization/src/test_support.rs +++ b/crates/logical-asap-optimization/src/test_support.rs @@ -111,10 +111,8 @@ use asap_types::ir::operator::operator_properties::{GroupKeys, Reduction, Source use asap_types::ir::properties::timing::{ apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; -use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{ColumnId, DataType, Field, Schema}; use asap_types::ir::{NonASAPOp, Predicate, ScalarExpr, TimeRangeKind}; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; /// A `TimeSeries("m")` scan over `[ts(0), value(1), labels...]`, time index 0, /// no unique key. @@ -236,13 +234,7 @@ pub fn timed(root: &Rc) -> Rc { pub fn at_ingestion(root: &Rc) -> Rc { apply_physical_properties( root, - &PhysicalPropertiesAssignment::with_default( - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), - ), + &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)), &mut NodeToTimedNodeCache::new(), ) .expect("at-ingestion physical properties apply") diff --git a/crates/physical-asap-optimization/src/catalog/configurations.rs b/crates/physical-asap-optimization/src/catalog/configurations.rs index 956fe25c3..818498197 100644 --- a/crates/physical-asap-optimization/src/catalog/configurations.rs +++ b/crates/physical-asap-optimization/src/catalog/configurations.rs @@ -9,10 +9,7 @@ use asap_types::stages::{ProducerCandidates, ProducerSetInterner}; use std::collections::HashMap; -use crate::{ - kept_across_evaluations_at_ingestion, kept_across_evaluations_at_query_time, - kept_for_one_evaluation, physical_properties as properties, summary_keep_eligibility, -}; +use crate::summary_keep_eligibility; use asap_types::ir::operator::{agg_has_exact_per_entity_kernel, Reduction}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode}; @@ -40,7 +37,7 @@ pub fn may_keep_across_evaluations_per_sole_reader_query( data: &DataWorkload, query_time_results_retained: bool, ) -> Vec { - if properties != kept_across_evaluations_at_query_time() + if properties != PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME || !matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) || !query_time_results_retained { @@ -141,42 +138,44 @@ pub fn enumerate_candidate_configurations( .enumerate() .filter_map(|(query, reached)| reached.then_some(query)) .collect::>(); - let mut alternatives = vec![properties(ExecutionTiming::QueryTime, Lifetime::None)]; + let mut alternatives = vec![PhysicalProperties::NOT_KEPT_AT_QUERY_TIME]; if summary { - alternatives.push(kept_for_one_evaluation()); + alternatives.push(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); if queries.iter().any(|&query| { summary_properties_allowed( node, &[query], - kept_across_evaluations_at_ingestion(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, entries, data, query_time_results_retained, ) }) { - alternatives.push(kept_across_evaluations_at_ingestion()); + alternatives + .push(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION); } if matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) && queries.iter().any(|&query| { summary_properties_allowed( node, &[query], - kept_across_evaluations_at_query_time(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, entries, data, query_time_results_retained, ) }) { - alternatives.push(kept_across_evaluations_at_query_time()); + alternatives + .push(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME); } } else if !forced_query { - alternatives.push(properties(ExecutionTiming::IngestionTime, Lifetime::None)); + alternatives.push(PhysicalProperties::NOT_KEPT_AT_INGESTION); } // Potential reach only generates the choice. Selected-reader cardinality // and Stage 2's highest-shared rule determine actual eligibility. if !summary && queries.len() >= 2 { - alternatives.push(kept_for_one_evaluation()); + alternatives.push(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); } // Configurations the deployment cannot run are not generated; each is // recorded as pruned. @@ -226,7 +225,7 @@ pub fn enumerate_candidate_configurations( query_time_results_retained, ), }); - if properties == kept_for_one_evaluation() { + if properties == PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION { if !summary { reader_constraints.push(ReaderConstraint::HighestSharedOneEvaluation { candidate: id, diff --git a/crates/physical-asap-optimization/src/catalog/realize.rs b/crates/physical-asap-optimization/src/catalog/realize.rs index c07bacacb..a6cc59db5 100644 --- a/crates/physical-asap-optimization/src/catalog/realize.rs +++ b/crates/physical-asap-optimization/src/catalog/realize.rs @@ -3,7 +3,7 @@ //! No fallback modes are chosen. Physical rewrites or timing splits that change //! candidate identity are rejected until represented by physical enumeration. //! This validates execution legality, not cost estimates or accuracy targets. -use asap_types::physical::Lifetime; +use asap_types::physical::PhysicalProperties; use std::collections::HashMap; use std::rc::Rc; @@ -39,15 +39,11 @@ pub fn realize_selected_candidates( } let rebuilt = reconstruct_selected_candidates(physical_candidates, selected)?; // `reconstruct_selected_candidates` checked every selected candidate exists. - // Each selected node's assignment: its properties when it is kept, - // `None` when it is not. - let assignments: Vec<_> = selected + // Each selected node's physical properties. + let assignments: Vec = selected .candidate_of_node .iter() - .map(|id| { - let properties = physical_candidates.candidates[id.0].properties; - properties.lifetime().is_kept().then_some(properties) - }) + .map(|id| physical_candidates.candidates[id.0].properties) .collect(); let mut node_by_pointer = HashMap::new(); for (node, operator_node) in rebuilt.operator_node_of_selected_node.iter().enumerate() { @@ -64,24 +60,28 @@ pub fn realize_selected_candidates( query_time_results_retained, &mut |logical, _, options| { let node = node_by_pointer.get(&logical).copied(); - let requested = if let Some(node) = node { + // A node outside the selection is not kept. + let requested = node.map_or(PhysicalProperties::NOT_KEPT_AT_QUERY_TIME, |node| { seen[node] = true; assignments[node] - } else { - None - }; - if !options.contains(&requested) { + }); + // The option keeping it as requested; option `None` (not kept) + // for a requested lifetime `None`, at either timing. + let chosen = options.iter().position(|option| match option { + Some(kept) => *kept == requested, + None => !requested.lifetime().is_kept(), + }); + if chosen.is_none() { let message = format!( - "selected kept output {requested:?} is not offered for selected node {node:?}" + "selected properties {requested:?} are not offered for selected node {node:?}" ); assignment_error = Some(if node.is_some() { PhysicalCandidateError::RejectedAssignment(message) } else { PhysicalCandidateError::InvalidOrUnsupported(message) }); - return None; } - Some(requested) + chosen }, ) .map_err(|error| error.to_string())?; @@ -97,8 +97,8 @@ pub fn realize_selected_candidates( physical.dag.validate().map_err(|error| error.to_string())?; let physical_outputs = ordered_output_references(&physical.roots); let identities = paired_node_identities(&rebuilt.outputs, &physical_outputs)?; - for (node, kept) in assignments.iter().enumerate() { - if kept.is_some() && !seen[node] { + for (node, properties) in assignments.iter().enumerate() { + if properties.lifetime().is_kept() && !seen[node] { // The decoder already established node identity. Stage 2 did // not offer this selected node (e.g. a lower shared non-summary), // so the assignment is infeasible rather than an adapter failure. @@ -116,8 +116,7 @@ pub fn realize_selected_candidates( .get(&Rc::as_ptr(&operator_node)) .cloned() .ok_or_else(|| format!("selected node {node} has no physical identity"))?; - let lifetime = assignments[node].map_or(Lifetime::None, |kept| kept.lifetime()); - if physical.lifetime != lifetime { + if physical.lifetime != assignments[node].lifetime() { return Err(format!( "selected node {node} lifetime changed during physical reconstruction" )); @@ -232,7 +231,7 @@ mod tests { use asap_types::workload::QueryRecurrence; /// Add a node running `candidate` and, for each input, a node of its - /// first not_kept producer (else its first producer), + /// first producer that is not kept (else its first producer), /// recursively; returns the new node. fn select_from( physical: &PhysicalASAPMemoCandidates, diff --git a/crates/physical-asap-optimization/src/lib.rs b/crates/physical-asap-optimization/src/lib.rs index c7a713656..497565b7b 100644 --- a/crates/physical-asap-optimization/src/lib.rs +++ b/crates/physical-asap-optimization/src/lib.rs @@ -132,9 +132,7 @@ use asap_types::ir::{ Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, ScalarExpr, SchemaDerivationError, SortKey, }; -use asap_types::physical::Medium; -use asap_types::physical::PhysicalWorkloadPlan; -use asap_types::physical::{Lifetime, PhysicalProperties}; +use asap_types::physical::{PhysicalProperties, PhysicalWorkloadPlan}; use asap_types::workload::{ DataArrival, DataWorkload, Predictability, QueryRecurrence, QueryWorkloadEntry, RepeatedDemand, }; @@ -335,7 +333,7 @@ fn summary_reader_eligibility( /// ingestion time over one that is not; Stage 3 prices each. /// `at_ingestion` records why ingestion is ruled out when it is (e.g. /// `Filtered`, `NotRepeated`). Each physical candidate carries the -/// resulting assignment ([`PhysicalWorkloadPlan::lifetime`]). +/// resulting lifetimes on its `dag` nodes. #[derive(Debug, Clone)] pub(crate) struct KeptOutputCandidate { /// The build in the implemented DAG. @@ -358,13 +356,17 @@ impl KeptOutputCandidate { pub(crate) fn options(&self) -> Vec> { let mut options = vec![None]; if self.at_ingestion.is_ok() { - options.push(Some(kept_across_evaluations_at_ingestion())); + options.push(Some( + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + )); } if self.readers.len() > 1 { - options.push(Some(kept_for_one_evaluation())); + options.push(Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION)); } if self.may_keep_across_evaluations { - options.push(Some(kept_across_evaluations_at_query_time())); + options.push(Some( + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + )); } options } @@ -445,51 +447,20 @@ pub fn optimize_physical_asap( .collect() } -/// Stage 2 for one CandidateLogicalASAPDAG and one physical properties -/// assignment: the physical candidate [`optimize_physical_asap`] lists for -/// it. `choose(readers)` gives the option for each kept-output -/// candidate (each summary build in discovery order, query by query, each -/// query's builds as a walk from its root meets them, then each highest -/// shared non-summary node in the same order), `readers` being the queries -/// that read it. `None` when -/// a chosen option is not one of the build's, or the assignment -/// materializes a build at ingestion time above one at query time. -#[cfg(feature = "test-support")] -pub fn optimize_physical_asap_assigned( - from_logical: &str, - roots: &[QueryRoot], - entries: &[QueryWorkloadEntry], - data: &DataWorkload, - query_time_results_retained: bool, - choose: &mut dyn FnMut(&[usize]) -> Option>, -) -> Result, PhysicalASAPOptimizationError> { - optimize_physical_asap_chosen( - from_logical, - roots, - entries, - data, - query_time_results_retained, - &mut |_, readers, _| choose(readers), - ) -} - /// [`optimize_physical_asap_chosen`]'s choice per kept-output -/// candidate: from the logical node it implements, its readers and its -/// options. `None` rejects the assignment. -pub(crate) type ChoosePhysicalProperties<'a> = dyn FnMut( - *const OperatorNode, - &[usize], - &[Option], - ) -> Option> - + 'a; +/// candidate, from the logical node it implements, its readers and its +/// options (`None` = not kept, always first): the index of the chosen +/// option, or `None` to reject the assignment. +pub(crate) type ChoosePhysicalProperties<'a> = + dyn FnMut(*const OperatorNode, &[usize], &[Option]) -> Option + 'a; /// Stage 2 for one CandidateLogicalASAPDAG and one physical properties /// assignment chosen node by node: `choose(logical, readers, options)` /// gives the option for each kept-output candidate, `logical` being /// the address of the logical node of `roots` it implements (null when it /// implements none, e.g. a node the implementation adds) and `readers` the -/// queries that read it. `None` when `choose` rejects, a chosen option is -/// not one of the candidate's, or the assignment materializes a build at ingestion time +/// queries that read it. `None` when `choose` rejects, a chosen index is +/// out of range, or the assignment keeps a build at ingestion time /// above one at query time. The search that decodes one plan from a model /// solution uses it to build that plan alone, not every assignment. pub(crate) fn optimize_physical_asap_chosen( @@ -513,12 +484,12 @@ pub(crate) fn optimize_physical_asap_chosen( .copied() .unwrap_or(std::ptr::null()); let options = kept_output_candidate.options(); - let Some(m) = choose(logical, &kept_output_candidate.readers, &options) - .filter(|m| options.contains(m)) + let Some(&chosen) = choose(logical, &kept_output_candidate.readers, &options) + .and_then(|index| options.get(index)) else { return Ok(None); }; - assignment.push(m); + assignment.push(chosen); } let nodes: Vec<_> = kept_output_candidates .iter() @@ -550,8 +521,8 @@ fn assigned_candidate( ) -> Result { let mut options = PhysicalPropertiesAssignment::default(); for (kept_output_candidate, kept) in kept_output_candidates.iter().zip(&assignment) { - if kept.is_some() { - options.set(&kept_output_candidate.node, *kept); + if let Some(kept) = *kept { + options.set(&kept_output_candidate.node, kept); } } let operators: Vec> = implemented @@ -572,25 +543,11 @@ fn assigned_candidate( Ok(apply_physical_properties(node, &options, &mut timing)?) })?; let dag = compile_physical_asap_workload_with_node_ids(&timed)?.dag; - let lifetime = dag - .nodes - .iter() - .filter(|n| { - matches!( - n.payload, - Operator::ASAP( - ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } - ) - ) || n.lifetime.is_kept() - }) - .map(|n| (n.id, n.lifetime)) - .collect(); Ok(PhysicalWorkloadPlan { id: String::new(), from_logical: from_logical.to_string(), roots: timed, dag, - lifetime, }) } @@ -729,7 +686,10 @@ pub(crate) fn find_kept_output_candidates( // Only this build and the builds below it at ingestion time. let mut trial = PhysicalPropertiesAssignment::default(); for &v in below[c].iter().chain([&c]) { - trial.set(&nodes[v], Some(kept_across_evaluations_at_ingestion())); + trial.set( + &nodes[v], + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); } apply_physical_properties(node, &trial, &mut NodeToTimedNodeCache::new()) .map(|_| ()) @@ -1216,39 +1176,6 @@ pub mod test_support { } } -/// `timing` and `lifetime`, a pair Stage 2 only builds when valid. -pub(crate) fn physical_properties( - timing: ExecutionTiming, - lifetime: Lifetime, -) -> PhysicalProperties { - PhysicalProperties::new(timing, lifetime).expect("Stage 2 builds only valid pairs") -} - -/// Query time, kept in memory until the evaluation's readers finish. -pub(crate) fn kept_for_one_evaluation() -> PhysicalProperties { - physical_properties( - ExecutionTiming::QueryTime, - Lifetime::OneEvaluation(Medium::Memory), - ) -} - -/// Ingestion time, kept in memory until a query reads it. -pub(crate) fn kept_across_evaluations_at_ingestion() -> PhysicalProperties { - physical_properties( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) -} - -/// Query time, kept in memory across evaluations (a tumbling-window chain -/// that builds its newest window at each evaluation). -pub(crate) fn kept_across_evaluations_at_query_time() -> PhysicalProperties { - physical_properties( - ExecutionTiming::QueryTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) -} - #[cfg(test)] mod tests { use super::*; @@ -1258,6 +1185,7 @@ mod tests { use asap_types::ir::properties::AccuracyTarget; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::ASAPOp; + use asap_types::physical::{Lifetime, Medium}; // Candidate-local implementation must leave another group's canonical root untouched. #[test] @@ -1627,14 +1555,13 @@ mod tests { pass2_candidates.pop().unwrap().roots.unwrap().remove(0) } - const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); - /// The lifetimes `candidate` chose other than `None`, by node. - fn materialized(candidate: &PhysicalWorkloadPlan) -> Vec { + fn kept(candidate: &PhysicalWorkloadPlan) -> Vec { candidate - .lifetime - .values() - .copied() + .dag + .nodes + .iter() + .map(|node| node.lifetime) .filter(|lifetime| lifetime.is_kept()) .collect() } @@ -1796,17 +1723,17 @@ mod tests { let [b2, b1] = &candidates[..] else { unreachable!() }; - assert!(!b2.materializes_any()); + assert!(!b2.keeps_any()); assert!(b2 .dag .nodes .iter() .all(|n| n.output_state.timing == ExecutionTiming::QueryTime)); - assert_eq!(materialized(b1), [KEPT_ACROSS]); + assert_eq!(kept(b1), [Lifetime::AcrossEvaluations(Medium::Memory)]); let [chain] = &node_of(b1, "SummaryTumblingWindowChain")[..] else { panic!("one chain") }; - assert_eq!(chain.lifetime, KEPT_ACROSS); + assert_eq!(chain.lifetime, Lifetime::AcrossEvaluations(Medium::Memory)); assert_eq!(chain.timing, Some(ExecutionTiming::IngestionTime)); for below in OperatorNode::reachable(chain) { assert_eq!(below.timing, Some(ExecutionTiming::IngestionTime)); @@ -2105,7 +2032,10 @@ mod tests { false, ) .unwrap(); - assert_eq!(materialized(&candidates[1]), [KEPT_ACROSS]); + assert_eq!( + kept(&candidates[1]), + [Lifetime::AcrossEvaluations(Medium::Memory)] + ); // The same build with a filter. let QueryRoot::Operator(node) = &root else { @@ -2259,7 +2189,7 @@ mod tests { optimize_physical_asap("L1", &roots, &[], &DataWorkload::default(), false).unwrap(); assert_eq!(candidates.len(), 2); assert_eq!( - materialized(&candidates[1]), + kept(&candidates[1]), [Lifetime::OneEvaluation(Medium::Memory)] ); let [build] = &node_of(&candidates[1], "SummaryAgg")[..] else { @@ -2386,7 +2316,10 @@ mod tests { .iter() .map(|c| (c.node.operator.kind_name(), c.readers.clone(), c.options())) .collect(); - let options = vec![None, Some(kept_for_one_evaluation())]; + let options = vec![ + None, + Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION), + ]; assert_eq!( found, [ diff --git a/crates/physical-asap-optimization/src/split_by_timing.rs b/crates/physical-asap-optimization/src/split_by_timing.rs index 23f8fb09f..a0499d496 100644 --- a/crates/physical-asap-optimization/src/split_by_timing.rs +++ b/crates/physical-asap-optimization/src/split_by_timing.rs @@ -18,7 +18,7 @@ type Copies = HashMap<(*const OperatorNode, ExecutionTiming), (Rc, /// copied, one copy per timing; a sub-DAG reached with one timing stays one /// `Rc`, shared by the roots that read it. Returns the (possibly rewritten) /// roots, in order, and `assignment` remapped onto them: a rebuilt node -/// keeps its original's explicit materialization. +/// keeps its original's assignment. pub fn split_shared_by_timing( roots: &[Rc], assignment: &PhysicalPropertiesAssignment, @@ -108,9 +108,7 @@ pub fn split_shared_by_timing( .collect(); let mut remapped = assignment.clone(); for (original, copy) in copies.values() { - if let Some(kept) = assignment.get(original) { - remapped.set(copy, kept); - } + remapped.copy_assignment(original, copy); } (split, remapped) } @@ -134,11 +132,6 @@ mod tests { const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); - /// Kept at ingestion time across evaluations. - fn at_ingestion() -> Option { - PhysicalProperties::new(ExecutionTiming::IngestionTime, KEPT_ACROSS).ok() - } - fn scan() -> Rc { OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { source: Source::TimeSeries { metric: "m".into() }, @@ -247,7 +240,9 @@ mod tests { assert_eq!( apply_physical_properties( &root, - &PhysicalPropertiesAssignment::with_default(at_ingestion()), + &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed( + std::slice::from_ref(&root) + ), &mut NodeToTimedNodeCache::new() ) .err(), @@ -258,7 +253,9 @@ mod tests { ); let (split, assignment) = split_shared_by_timing( std::slice::from_ref(&root), - &PhysicalPropertiesAssignment::with_default(at_ingestion()), + &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( + &root, + )), ); assert!(apply_physical_properties( &split[0], @@ -279,7 +276,10 @@ mod tests { })) .unwrap(); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&summary, at_ingestion()); + assignment.set( + &summary, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let (split, assignment) = split_shared_by_timing(std::slice::from_ref(&root), &assignment); let timed = apply_physical_properties(&split[0], &assignment, &mut NodeToTimedNodeCache::new()) @@ -310,7 +310,10 @@ mod tests { concat(vec![raw, Rc::clone(&common)]), ]; let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&summary, at_ingestion()); + assignment.set( + &summary, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed_unsplit = { let mut cache = NodeToTimedNodeCache::new(); roots @@ -357,9 +360,18 @@ mod tests { .with_timing(Some(ExecutionTiming::QueryTime)), ); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&summary, at_ingestion()); - assignment.set(&state, at_ingestion()); - assignment.set(&read, at_ingestion()); + assignment.set( + &summary, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + assignment.set( + &state, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + assignment.set( + &read, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let (split, assignment) = split_shared_by_timing(&[pair, read], &assignment); let mut cache = NodeToTimedNodeCache::new(); let timed: Result, _> = split @@ -372,7 +384,7 @@ mod tests { ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - assigned: at_ingestion().unwrap(), + assigned: PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, } ) ); diff --git a/crates/plan-selection/src/groups.rs b/crates/plan-selection/src/groups.rs index 565b32ee9..35363f45c 100644 --- a/crates/plan-selection/src/groups.rs +++ b/crates/plan-selection/src/groups.rs @@ -1093,7 +1093,7 @@ fn window_read_through(path: &[&PhysicalASAPDAGNode]) -> ScanWindow { tumbling_window_width_ms, .. }) if node.output_state.timing == ExecutionTiming::QueryTime - && matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) => + && node.lifetime.is_across_evaluations() => { u128::from(*tumbling_window_width_ms) } @@ -1307,12 +1307,9 @@ fn retained_pane_options( ) -> Vec { let node = &nodes[chain.0]; let kept = matches!( - (&node.payload, node.lifetime), - ( - Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }), - Lifetime::AcrossEvaluations(_) - ) - ); + node.payload, + Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) + ) && node.lifetime.is_across_evaluations(); if !kept { return vec![asap_cost::tumbling_windows_of(node)]; } diff --git a/crates/plan-selection/src/groups/tests.rs b/crates/plan-selection/src/groups/tests.rs index 82df42489..4ac11facf 100644 --- a/crates/plan-selection/src/groups/tests.rs +++ b/crates/plan-selection/src/groups/tests.rs @@ -220,11 +220,7 @@ fn dominance_needs_every_condition() { ( "lifetime", DominanceKey { - properties: PhysicalProperties::new( - ExecutionTiming::QueryTime, - Lifetime::OneEvaluation(Medium::Memory), - ) - .unwrap(), + properties: PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, ..key.clone() }, ), @@ -493,11 +489,7 @@ fn shared_middle() -> PhysicalASAPMemoCandidates { let candidates = vec![ candidate(0, &[], false), PhysicalCandidate { - properties: PhysicalProperties::new( - ExecutionTiming::QueryTime, - Lifetime::OneEvaluation(Medium::Memory), - ) - .unwrap(), + properties: PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, ..candidate(1, &[&[0]], false) }, candidate(2, &[&[1]], true), diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index e641a8b72..3025d7c3f 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -3462,7 +3462,9 @@ mod tests { .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryAgg { .. }))) .expect("a KLL state"); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&state, kept); + if let Some(kept) = kept { + assignment.set(&state, kept); + } let timed = apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); asap_types::ir::physical_export::compile_physical_asap_workload_with_node_ids(&[ @@ -3525,26 +3527,13 @@ mod tests { assert!(range.detail.contains("keep"), "{}", range.detail); } - /// Kept `lifetime` at `timing`. - fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> Option { - Some(PhysicalProperties::new(timing, lifetime).unwrap()) - } - /// Kept in memory at ingestion time until a query reads it. - fn at_ingestion() -> Option { - kept( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - } + const AT_INGESTION: Option = + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION); /// Kept in memory at query time for one evaluation. - fn at_query() -> Option { - kept( - ExecutionTiming::QueryTime, - Lifetime::OneEvaluation(Medium::Memory), - ) - } + const AT_QUERY: Option = + Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); fn node_of(dag: &PhysicalASAPDAG, pick: impl Fn(&Payload) -> bool) -> PhysicalASAPNodeId { dag.nodes.iter().find(|n| pick(&n.payload)).unwrap().id @@ -3581,7 +3570,7 @@ mod tests { /// node scales with that rate. #[test] fn ingestion_time_node_is_priced_per_second_of_arriving_rows() { - let dag = kll_dag(at_ingestion()); + let dag = kll_dag(AT_INGESTION); let (fast, slow) = ( priced(&dag, &[repeating(1_000)]), priced(&dag, &[repeating(10_000)]), @@ -3613,7 +3602,7 @@ mod tests { let settings = unit_costs(|c| c.cost_per_memory_byte_second = w); price(dag, &recurrences(1), &data(), &settings).unwrap() }; - for kept in [at_ingestion(), at_query(), None] { + for kept in [AT_INGESTION, AT_QUERY, None] { let dag = kll_dag(kept); let build = node_of(&dag, is_build); let (with, without) = (cost(&dag, 1.25e-7), cost(&dag, 0.0)); @@ -3626,7 +3615,7 @@ mod tests { // each sees its series' 12 samples: the 120 000 rows of its // source's 1-min window (data()'s 10 000 rows per second over its // five sources); at ingestion time its samples are unknown. - let samples = if kept == at_ingestion() { + let samples = if kept == AT_INGESTION { StateInputRows::UNKNOWN } else { StateInputRows { @@ -3635,7 +3624,7 @@ mod tests { } }; let state = 10_000.0 * summary_shape(family, samples).1 as f64; - let byte_seconds = if kept == at_ingestion() { + let byte_seconds = if kept == AT_INGESTION { 2.0 * state } else { let evaluation_s = with.usage.latency_per_query[0].total_ms() / 1_000.0; @@ -3694,7 +3683,7 @@ mod tests { (query.to_string(), dag) }) .collect(); - for kept in [at_ingestion(), at_query(), None] { + for kept in [AT_INGESTION, AT_QUERY, None] { dags.push((format!("{kept:?}"), kll_dag(kept))); } for (name, dag) in &dags { @@ -4652,18 +4641,20 @@ mod tests { let state = |dag: &PhysicalASAPDAG| node_of(dag, is_build); for (on_disk, in_memory) in [ ( - kept( + PhysicalProperties::new( ExecutionTiming::IngestionTime, Lifetime::AcrossEvaluations(Medium::Disk), - ), - at_ingestion(), + ) + .ok(), + AT_INGESTION, ), ( - kept( + PhysicalProperties::new( ExecutionTiming::QueryTime, Lifetime::OneEvaluation(Medium::Disk), - ), - at_query(), + ) + .ok(), + AT_QUERY, ), ] { let (disk_dag, memory_dag) = (kll_dag(on_disk), kll_dag(in_memory)); diff --git a/crates/planner/src/installable.rs b/crates/planner/src/installable.rs index 317425809..1160405a6 100644 --- a/crates/planner/src/installable.rs +++ b/crates/planner/src/installable.rs @@ -791,10 +791,9 @@ fn report_of( #[cfg(test)] mod tests { use super::*; - use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::{SketchAlgorithm, StatisticKind, SupportedSummary}; use asap_types::ir::{NonASAPOp, Operator}; - use asap_types::physical::{Lifetime, PhysicalProperties}; + use asap_types::physical::PhysicalProperties; thread_local! { /// The plan nodes handed to the executor's compiler by the views' @@ -951,7 +950,6 @@ mod tests { use asap_types::ir::{ apply_physical_properties, NodeToTimedNodeCache, OperatorNode, TimeRangeKind, }; - use asap_types::physical::Medium; use std::time::Duration; let scan = OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { source: Source::TimeSeries { @@ -1002,11 +1000,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &merged, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&merged, &assignment, &mut NodeToTimedNodeCache::new()) @@ -1046,11 +1040,7 @@ mod tests { for node in tumbling_windows.iter().chain([&merge]) { assignment.set( node, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let timed = diff --git a/crates/planner/tests/deployment_accuracy_model.rs b/crates/planner/tests/deployment_accuracy_model.rs index 6267590ec..8edb9f6ec 100644 --- a/crates/planner/tests/deployment_accuracy_model.rs +++ b/crates/planner/tests/deployment_accuracy_model.rs @@ -115,7 +115,7 @@ fn physical_candidates( &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(None), + &mut |_, _, _| Some(0), // option 0: not kept ) .unwrap() .expect("query-time fixture is executable"); diff --git a/crates/planner/tests/per_sample_updater.rs b/crates/planner/tests/per_sample_updater.rs index b8f83f1e5..94af31123 100644 --- a/crates/planner/tests/per_sample_updater.rs +++ b/crates/planner/tests/per_sample_updater.rs @@ -24,7 +24,7 @@ use time_series::{series_identity, series_labels, time_series_tables, RawDataSam const EVALUATION_MS: i64 = 3_600_000; #[tokio::test] -async fn per_sample_updates_build_the_materialized_tumbling_window_the_plan_refreshes() { +async fn per_sample_updates_build_the_kept_tumbling_window_the_plan_refreshes() { // What the user writes: the 5-minute rate of a counter, every minute, // exactly, over 1,000 series sampled every 15 s. let workload: PlanningWorkload = serde_json::from_str( diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index ea7377231..0adf208f3 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -25,14 +25,13 @@ use asap_planner::{ SelectionBox, Stage1ToStage3Pass, UserInput, }; use asap_types::ir::operator::Source; -use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::schema::schema_support::with_promql_series_identity; use asap_types::ir::schema::{FieldDataType, SketchAlgorithm, SketchParams}; use asap_types::ir::{ apply_physical_properties_to_roots, ASAPOp, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, }; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; +use asap_types::physical::{Lifetime, PhysicalProperties}; use asap_types::stages::HowToComputeAggregateMeasure; use asap_types::stages::PruneReason; use futures::{executor::block_on, StreamExt}; @@ -1577,13 +1576,10 @@ fn untime( ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } | ASAPOp::SummaryMerge { .. }, - ) if node.lifetime.is_kept() => Some( - PhysicalProperties::new(node.timing.expect("a timed plan"), node.lifetime).unwrap(), - ), + ) if node.lifetime.is_kept() => node.physical_properties(), _ => None, }; - let kept = store(node).or(own); - if kept.is_some() { + if let Some(kept) = store(node).or(own) { assignment.set(©, kept); } untimed.insert(Rc::as_ptr(node), Rc::clone(©)); @@ -1592,24 +1588,14 @@ fn untime( /// Every `SummaryAgg` built at ingestion time. fn summaries_at_ingestion(node: &OperatorNode) -> Option { - matches!(node.asap(), Some(ASAPOp::SummaryAgg { .. })).then(|| { - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .unwrap() - }) + matches!(node.asap(), Some(ASAPOp::SummaryAgg { .. })) + .then(|| PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION) } /// Every `SummaryMerge` built at query time and kept across evaluations. fn merges_kept(node: &OperatorNode) -> Option { - matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })).then(|| { - PhysicalProperties::new( - ExecutionTiming::QueryTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .unwrap() - }) + matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })) + .then(|| PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME) } /// Exact PromQL `queries`, every minute, over 6 ingesting series of `m` diff --git a/crates/planner/tests/summary_sharing.rs b/crates/planner/tests/summary_sharing.rs index 65e8a3629..a8bf5ddc4 100644 --- a/crates/planner/tests/summary_sharing.rs +++ b/crates/planner/tests/summary_sharing.rs @@ -142,7 +142,7 @@ fn composed_summary_candidates( &entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(None), + &mut |_, _, _| Some(0), // option 0: not kept ) .unwrap() .expect("supported physical computation"); @@ -200,7 +200,7 @@ fn shared_kll_candidate(workload: &PlanningWorkload) -> asap_types::physical::Ph &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(None), + &mut |_, _, _| Some(0), // option 0: not kept ) .unwrap() .unwrap(); diff --git a/crates/types/src/ir/materialized_view.rs b/crates/types/src/ir/materialized_view.rs index 10262e043..8a86a2e18 100644 --- a/crates/types/src/ir/materialized_view.rs +++ b/crates/types/src/ir/materialized_view.rs @@ -79,7 +79,6 @@ use crate::ir::operator::non_asap::NonASAPOp; use crate::ir::operator::operator_properties::Source; use crate::ir::properties::execution_data_state::ExecutionTiming; use crate::ir::properties::summary_coverage::{CoverageError, SelectionBox, SummaryCoverage}; -use crate::physical::Lifetime; /// One materialized view of a DAG: what its stored state is, what it is /// refreshed from, when, and for how long it is kept. @@ -401,7 +400,7 @@ impl PhysicalASAPDAG { if let Some(node) = self .nodes .iter() - .find(|node| is_view(node) && node.retention_ms.is_none()) + .find(|node| node.lifetime.is_across_evaluations() && node.retention_ms.is_none()) { return Err(InstallableDagError::ViewWithoutRetention { node_id: node.id }); } @@ -730,7 +729,7 @@ impl PhysicalASAPDAG { let views: HashSet = self .nodes .iter() - .filter(|node| is_view(node)) + .filter(|node| node.lifetime.is_across_evaluations()) .map(|node| node.id) .collect(); // The IR of each node, which coverage is derived from. @@ -1161,9 +1160,3 @@ fn with_replaced( } replace(node, old, new, &mut HashMap::new()) } - -/// Whether `node` is a materialized view: its output is kept across -/// evaluations. -fn is_view(node: &PhysicalASAPDAGNode) -> bool { - matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) -} diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index 59ee2424c..b02f70ae4 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -15,7 +15,7 @@ use crate::ir::properties::guarantee::AccuracyGuarantee; use crate::ir::properties::summary_coverage::{NodeToSummaryCoverageCache, SummaryCoverage}; use crate::ir::schema::Schema; use crate::ir::SchemaDerivationError; -use crate::physical::Lifetime; +use crate::physical::{Lifetime, PhysicalProperties}; /// The output category of an operator, derived from the operation and its /// inputs. Matching column schemas do not make categories interchangeable. @@ -107,6 +107,12 @@ pub struct OperatorNode { } impl OperatorNode { + /// Its timing and lifetime, once [`crate::ir::apply_physical_properties`] + /// has timed it; `None` before. + pub fn physical_properties(&self) -> Option { + PhysicalProperties::new(self.timing?, self.lifetime).ok() + } + /// Build a node, deriving its schema and output category. Fails when the /// schema cannot be derived (a column reference out of range, a reserved /// ASAP operator, ...). diff --git a/crates/types/src/ir/physical_export.rs b/crates/types/src/ir/physical_export.rs index e5bfc5edc..2afad5382 100644 --- a/crates/types/src/ir/physical_export.rs +++ b/crates/types/src/ir/physical_export.rs @@ -30,7 +30,7 @@ use crate::ir::properties::timing::{ }; use crate::ir::properties::timing::{data_state, is_keepable_state_output}; use crate::ir::schema::{FieldDataType, Schema}; -use crate::physical::{Lifetime, PhysicalProperties}; +use crate::physical::{InvalidPhysicalProperties, Lifetime, PhysicalProperties}; /// A node's operator, with each child replaced by its node id. pub type PhysicalASAPOperatorPayload = Operator; @@ -92,6 +92,14 @@ pub struct PhysicalASAPDAGNode { pub retention_ms: Option, } +impl PhysicalASAPDAGNode { + /// Its timing (`output_state.timing`) and lifetime, unless they cannot + /// go together. + pub fn physical_properties(&self) -> Result { + PhysicalProperties::new(self.output_state.timing, self.lifetime) + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct PhysicalASAPDAGEdge { @@ -172,15 +180,17 @@ pub struct PhysicalASAPDAG { #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum PhysicalASAPDAGValidationError { - #[error( - "node {node:?} runs at {timing:?} with lifetime {lifetime:?}: a timing and lifetime that \ - cannot go together, or a summary build that is not kept outside query time" - )] + /// A node whose timing and lifetime cannot go together: a planner bug. + #[error("node {node:?}: {reason}")] InvalidPhysicalProperties { node: PhysicalASAPNodeId, - timing: ExecutionTiming, - lifetime: Lifetime, + #[source] + reason: InvalidPhysicalProperties, }, + /// A summary build (or maintained population) that is not kept but does + /// not run at query time: a planner bug. + #[error("node {node:?} is a summary build that is not kept but does not run at query time")] + UnkeptSummaryBuildNotAtQueryTime { node: PhysicalASAPNodeId }, #[error("ingestion node {consumer:?} depends on query node {producer:?}")] QueryDependencyInIngestion { producer: PhysicalASAPNodeId, @@ -601,23 +611,26 @@ impl PhysicalASAPDAG { if nodes.insert(node.id, node).is_some() { return Err(PhysicalASAPDAGValidationError::DuplicateNodeId(node.id)); } - // A kept output's timing and lifetime must go together; a summary + // A node's timing and lifetime must go together; a summary // build that is not kept runs at query time. Any other node that // is not kept runs when its consumer runs. - let timing = node.output_state.timing; - if PhysicalProperties::new(timing, node.lifetime).is_err() - || (is_keepable_state_output(&node.payload) - && node.lifetime == Lifetime::None - && timing != ExecutionTiming::QueryTime) - { - return Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { + let properties = node.physical_properties().map_err(|reason| { + PhysicalASAPDAGValidationError::InvalidPhysicalProperties { node: node.id, - timing, - lifetime: node.lifetime, - }); + reason, + } + })?; + if is_keepable_state_output(&node.payload) + && properties == PhysicalProperties::NOT_KEPT_AT_INGESTION + { + return Err( + PhysicalASAPDAGValidationError::UnkeptSummaryBuildNotAtQueryTime { + node: node.id, + }, + ); } if node.retention_ms.is_some() - && !matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) + && !node.lifetime.is_across_evaluations() && !super::materialized_view::is_query_time_scan(node) { return Err(PhysicalASAPDAGValidationError::UnexpectedRetention(node.id)); diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index d200a56d1..c487d27c6 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -65,102 +65,126 @@ use crate::ir::properties::execution_data_state::{ DataPrimitive, ExecutionDataState, ExecutionDataStateError, ExecutionTiming, }; use crate::ir::schema::{DataType, FieldDataType, Schema}; -#[cfg(any(test, feature = "test-support"))] +#[cfg(test)] use crate::physical::Medium; use crate::physical::{Lifetime, PhysicalProperties}; -/// Whether each sub-DAG's output is kept, and with which timing and -/// lifetime (#509 §Materialization: "Materialization decides, for each -/// sub-DAG, whether its output is stored"). A sub-DAG is named by the node -/// whose output would be kept (by identity); any node may be assigned. A -/// node without an assignment: a `SummaryAgg` or `MaintainPopulation` takes -/// the default, every other node is not kept and runs when its consumer -/// runs. `Default` keeps no sub-DAG. +/// Which sub-DAG outputs are kept, and with which timing and lifetime +/// (#509 §Materialization: "Materialization decides, for each sub-DAG, +/// whether its output is stored"). A sub-DAG is named by the node whose +/// output is kept (by identity); any node may be assigned. A node without +/// an assignment is not kept: a summary build or `MaintainPopulation` then +/// runs at query time, every other node when its consumer runs. `Default` +/// keeps nothing. /// /// The assignment keeps every assigned node alive, so a later allocation /// cannot reuse its address and match a stale entry. #[derive(Clone, Default)] pub struct PhysicalPropertiesAssignment { - assigned: HashMap<*const OperatorNode, (Rc, Option)>, - unassigned: Option, + kept: HashMap<*const OperatorNode, (Rc, PhysicalProperties)>, } -/// Each assigned node as its operator kind and address, not its whole -/// sub-DAG. +/// Each kept node as its operator kind and address, not its whole sub-DAG. impl std::fmt::Debug for PhysicalPropertiesAssignment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let assigned: Vec<_> = self - .assigned + let kept: Vec<_> = self + .kept .iter() .map(|(ptr, (node, properties))| { (format!("{}@{ptr:p}", node.operator.kind_name()), properties) }) .collect(); f.debug_struct("PhysicalPropertiesAssignment") - .field("assigned", &assigned) - .field("unassigned", &self.unassigned) + .field("kept", &kept) .finish() } } impl PhysicalPropertiesAssignment { - /// Every `SummaryAgg` or `MaintainPopulation` not [`set`](Self::set) - /// explicitly takes `kept` where the DAG allows it: an ingestion-time - /// default over a sub-DAG that can only run at query time leaves that - /// sub-DAG not kept. - pub fn with_default(kept: Option) -> Self { - Self { - assigned: HashMap::new(), - unassigned: kept, + /// Keep the output of the sub-DAG `node` produces with `kept`'s timing + /// and lifetime. `kept` must keep the output (lifetime not `None`). + pub fn set(&mut self, node: &Rc, kept: PhysicalProperties) { + debug_assert!(kept.lifetime().is_kept(), "{kept:?} does not keep"); + self.kept.insert(Rc::as_ptr(node), (Rc::clone(node), kept)); + } + + /// Give `copy` the assignment of `original`, if it has one: for a node + /// rebuilt as a copy of another. + pub fn copy_assignment(&mut self, original: &OperatorNode, copy: &Rc) { + if let Some(kept) = self.get(original) { + self.set(copy, kept); } } - /// Assign the sub-DAG whose output `node` produces: kept with `kept`'s - /// timing and lifetime, or, for `None`, not kept (it runs when its - /// consumer runs). A `Some` with lifetime `None` is not an assignment of - /// a kept output. - pub fn set(&mut self, node: &Rc, kept: Option) { - debug_assert!(kept.is_none_or(|p| p.lifetime().is_kept())); - self.assigned - .insert(Rc::as_ptr(node), (Rc::clone(node), kept)); + /// Every summary build and `MaintainPopulation` reachable from `roots` + /// kept in memory at ingestion time where the DAG allows it: not under a + /// filter, and with nothing below it that can only run at query time. + #[cfg(any(test, feature = "test-support"))] + pub fn kept_at_ingestion_where_allowed(roots: &[Rc]) -> Self { + fn visit( + node: &Rc, + assignment: &mut PhysicalPropertiesAssignment, + visited: &mut std::collections::HashSet<*const OperatorNode>, + ) { + if !visited.insert(Rc::as_ptr(node)) { + return; + } + for child in node.children() { + visit(child, assignment, visited); + } + if node.timing.is_none() + && is_keepable_state_output(&node.operator) + && !is_filtered_build(node) + && !node + .children() + .iter() + .any(|child| forces_query_time(child, assignment, &mut HashMap::new())) + { + assignment.set( + node, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + } + } + let mut assignment = Self::default(); + let mut visited = std::collections::HashSet::new(); + for root in roots { + visit(root, &mut assignment, &mut visited); + } + assignment } - /// The explicit assignment of `node`, if any: `Some(None)` when it is - /// explicitly not kept. - pub fn get(&self, node: &OperatorNode) -> Option> { - self.assigned + /// How `node` is kept, if it is. + fn get(&self, node: &OperatorNode) -> Option { + self.kept .get(&(node as *const OperatorNode)) .map(|(_, kept)| *kept) } - /// The option `node` gets when `upstream_at_query_time` says whether - /// something below it can only run at query time. + /// How `node` is kept, checked against what is below it: + /// `upstream_at_query_time` says whether something below it can only + /// run at query time. fn resolve( &self, node: &OperatorNode, upstream_at_query_time: bool, ) -> Result, ExecutionDataStateError> { - let at_ingestion = |kept: Option| { - kept.is_some_and(|p| p.timing() == ExecutionTiming::IngestionTime) - }; match self.get(node) { - Some(m) if at_ingestion(m) && is_filtered_build(node) => { + Some(kept) + if kept.timing() == ExecutionTiming::IngestionTime && is_filtered_build(node) => + { Err(ExecutionDataStateError::FilteredSummaryAtIngestion { operator: node.operator.kind_name(), }) } - Some(m) if at_ingestion(m) && upstream_at_query_time => { + Some(kept) + if kept.timing() == ExecutionTiming::IngestionTime && upstream_at_query_time => + { Err(ExecutionDataStateError::UpstreamNotAtIngestion { operator: node.operator.kind_name(), }) } - Some(m) => Ok(m), - None if at_ingestion(self.unassigned) - && (upstream_at_query_time || is_filtered_build(node)) => - { - Ok(None) - } - None => Ok(self.unassigned), + kept => Ok(kept), } } } @@ -306,7 +330,9 @@ pub fn apply_physical_properties( // A root stored at ingestion time is read by the query; one that runs at // ingestion time without being stored there produces rows nothing reads. if timed.timing == Some(ExecutionTiming::IngestionTime) - && !kept_at_ingestion(&timed) + && !timed + .physical_properties() + .is_some_and(|p| p.readable_at(ExecutionTiming::QueryTime)) && data_state(&timed).map(|s| s.primitive) == Some(DataPrimitive::Raw) { return Err(ExecutionDataStateError::UnstoredIngestionRoot { @@ -347,7 +373,8 @@ pub fn apply_physical_properties_to_roots( } /// Validate the sub-DAG below `root` with every sub-DAG kept at ingestion time -/// where the DAG allows it ([`PhysicalPropertiesAssignment::with_default`]) and +/// where the DAG allows it +/// ([`PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed`]) and /// `root` consumed at `root_timing`. For planning-time legality checks of a /// candidate before it is assembled into a workload DAG: a candidate must stay /// executable if materialization later puts its states at ingestion time. @@ -357,7 +384,8 @@ pub fn validate_at_ingestion( root: &Rc, root_timing: ExecutionTiming, ) -> Result<(), ExecutionDataStateError> { - let assignment = all_at_ingestion(); + let assignment = + PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)); let mut cache = NodeToTimedNodeCache::new(); let mut forced = HashMap::new(); let timed = write(root, root_timing, &assignment, &mut cache, &mut forced)?; @@ -374,33 +402,16 @@ pub fn planned_data_state( consumer: ExecutionTiming, ) -> ExecutionDataState { let mut forced = HashMap::new(); - let (timing, _) = placement(node, consumer, &all_at_ingestion(), &mut forced) - .expect("a default assignment never fails"); + let assignment = + PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(node)); + let (timing, _) = placement(node, consumer, &assignment, &mut forced) + .expect("an assignment kept where allowed never fails"); ExecutionDataState { timing, primitive: primitive(node), } } -/// The assignment of [`validate_at_ingestion`] and [`planned_data_state`]. -#[cfg(any(test, feature = "test-support"))] -fn all_at_ingestion() -> PhysicalPropertiesAssignment { - PhysicalPropertiesAssignment::with_default(Some( - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .expect("ingestion time, kept across evaluations"), - )) -} - -/// Whether `node`'s output runs at ingestion time and is kept until a query -/// reads it. -fn kept_at_ingestion(node: &OperatorNode) -> bool { - node.timing == Some(ExecutionTiming::IngestionTime) - && matches!(node.lifetime, Lifetime::AcrossEvaluations(_)) -} - /// The timing and lifetime `node` takes when its consumer runs at /// `consumer`. fn placement( @@ -432,28 +443,27 @@ fn placement( // with the fixed timing is kept, one that needs the other timing is // an error. return match assignment.get(node) { - Some(Some(kept)) if kept.timing() != placed => Err( + Some(kept) if kept.timing() != placed => Err( ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: node.operator.kind_name(), fixed: placed, assigned: kept, }, ), - Some(Some(kept)) => Ok((placed, kept.lifetime())), - Some(None) => Ok((placed, Lifetime::None)), + Some(kept) => Ok((placed, kept.lifetime())), None => Ok((placed, node.lifetime)), }; } Ok(match &node.operator { Operator::ASAP(ASAPOp::SummaryEstimate { .. }) | Operator::ASAP(ASAPOp::EvaluatePopulation { .. }) => match assignment.get(node) { - Some(Some(kept)) if kept.timing() == ExecutionTiming::IngestionTime => { + Some(kept) if kept.timing() == ExecutionTiming::IngestionTime => { return Err(ExecutionDataStateError::UpstreamNotAtIngestion { operator: node.operator.kind_name(), }) } - Some(Some(kept)) => (ExecutionTiming::QueryTime, kept.lifetime()), - Some(None) | None => (ExecutionTiming::QueryTime, Lifetime::None), + Some(kept) => (ExecutionTiming::QueryTime, kept.lifetime()), + None => (ExecutionTiming::QueryTime, Lifetime::None), }, _ if is_keepable_state_output(&node.operator) || assignment.get(node).is_some() => { let upstream = upstream_at_query_time(forced); @@ -603,7 +613,9 @@ fn validate_asap( // `NonASAP` consumer does. if timing == ExecutionTiming::QueryTime && avail.timing == ExecutionTiming::IngestionTime - && !kept_at_ingestion(child) + && !child + .physical_properties() + .is_some_and(|p| p.readable_at(timing)) { return Err( ExecutionDataStateError::UnstoredIngestionInputUnderQueryTimeSummary { @@ -754,7 +766,9 @@ fn validate_non_asap( && (is_exact_accumulator_state(&child.schema).is_ok() || selects_states(node)); // A query-time consumer may read the stored output of a sub-DAG // materialized at ingestion time. - let reads_stored = timing == ExecutionTiming::QueryTime && kept_at_ingestion(child); + let reads_stored = child + .physical_properties() + .is_some_and(|p| p.readable_at(timing)); if (s.timing != timing && !reads_stored) || (s.primitive != DataPrimitive::Raw && !passes_state) { @@ -994,18 +1008,19 @@ mod tests { /// Apply with every sub-DAG kept at ingestion time where the DAG allows it, the /// placement whose edge rules these tests exercise. fn apply(root: &Rc) -> Result, ExecutionDataStateError> { - apply_physical_properties(root, &all_at_ingestion(), &mut NodeToTimedNodeCache::new()) + apply_physical_properties( + root, + &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( + root, + )), + &mut NodeToTimedNodeCache::new(), + ) } const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); - fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> Option { - Some(PhysicalProperties::new(timing, lifetime).unwrap()) - } - - /// Kept at ingestion time across evaluations. - fn at_ingestion() -> Option { - kept(ExecutionTiming::IngestionTime, KEPT_ACROSS) + fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> PhysicalProperties { + PhysicalProperties::new(timing, lifetime).unwrap() } fn child(node: &Rc) -> Rc { @@ -1016,7 +1031,7 @@ mod tests { /// it and its input run at query time; an explicit choice overrides the /// default and is recorded on the timed node. #[test] - fn default_assignment_materializes_nothing() { + fn default_assignment_keeps_nothing() { let summary = agg(scan(), kll()); let root = apply_physical_properties( &summary, @@ -1063,7 +1078,10 @@ mod tests { let inner = agg(scan(), exact_sum()); let outer = agg(Rc::clone(&inner), kll()); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&outer, at_ingestion()); + assignment.set( + &outer, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); assert_eq!( apply_physical_properties( &estimate(outer), @@ -1075,9 +1093,15 @@ mod tests { operator: "SummaryAgg" }) ); - assignment.set(&inner, at_ingestion()); + assignment.set( + &inner, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let outer = agg(Rc::clone(&inner), kll()); - assignment.set(&outer, at_ingestion()); + assignment.set( + &outer, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let root = apply_physical_properties( &estimate(outer), &assignment, @@ -1107,27 +1131,6 @@ mod tests { assert!(apply(&estimate(agg(inner, kll()))).is_ok()); } - /// A state not at ingestion time leaves the summary that reads it, when - /// that summary has no explicit assignment, not kept at query - /// time, as an evaluation below it would. - #[test] - fn query_time_state_moves_its_consuming_summary_to_query_time() { - let inner = agg(scan(), exact_sum()); - let outer = agg(Rc::clone(&inner), kll()); - let mut assignment = all_at_ingestion(); - assignment.set(&inner, None); - let root = apply_physical_properties( - &estimate(outer), - &assignment, - &mut NodeToTimedNodeCache::new(), - ) - .unwrap(); - let outer = child(&root); - assert_eq!(outer.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(outer.lifetime, Lifetime::None); - assert_eq!(child(&outer).timing, Some(ExecutionTiming::QueryTime)); - } - #[test] fn evaluation_can_feed_summary_construction_at_query_time() { let inner = estimate(agg(scan(), kll())); @@ -1238,11 +1241,14 @@ mod tests { /// at ingestion time are read by a query-time consumer, and a node that /// can only run at query time cannot be stored at ingestion time. #[test] - fn any_node_may_be_materialized() { + fn any_node_may_be_kept() { let tumbling_windows = max(scan()); let root = max(Rc::clone(&tumbling_windows)); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&tumbling_windows, at_ingestion()); + assignment.set( + &tumbling_windows, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); @@ -1255,7 +1261,10 @@ mod tests { let over_evaluation = max(estimate(agg(scan(), kll()))); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&over_evaluation, at_ingestion()); + assignment.set( + &over_evaluation, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); assert_eq!( apply_physical_properties( &over_evaluation, @@ -1304,7 +1313,10 @@ mod tests { .with_guarantee(None), ); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&filtered, at_ingestion()); + assignment.set( + &filtered, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); assert_eq!( apply_physical_properties( &estimate(Rc::clone(&filtered)), @@ -1361,15 +1373,21 @@ mod tests { assert_eq!(exported(&timed, "FinalizeExactAccumulator"), stored); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&state, at_ingestion()); - assignment.set(&read, at_ingestion()); + assignment.set( + &state, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + assignment.set( + &read, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); assert_eq!( apply_physical_properties(&read, &assignment, &mut NodeToTimedNodeCache::new()).err(), Some( ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - assigned: at_ingestion().unwrap(), + assigned: PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, } ) ); @@ -1380,7 +1398,10 @@ mod tests { #[test] fn debug_names_each_assigned_node_by_its_kind() { let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&agg(scan(), kll()), at_ingestion()); + assignment.set( + &agg(scan(), kll()), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let text = format!("{assignment:?}"); assert!(text.contains("SummaryAgg@"), "{text}"); assert!(!text.contains("fields"), "{text}"); @@ -1404,32 +1425,12 @@ mod tests { ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "Aggregate", fixed: ExecutionTiming::IngestionTime, - assigned: at_query.unwrap(), + assigned: at_query, } ) ); } - /// An explicit not kept on a node whose timing its candidate - /// fixed agrees with either timing: the node keeps its fixed timing and - /// records not kept. - #[test] - fn explicit_not_kept_keeps_a_fixed_timing() { - let read = Rc::new( - (*finalize(agg(scan(), exact_sum()))) - .clone() - .with_timing(Some(ExecutionTiming::QueryTime)), - ); - let root = max(Rc::clone(&read)); - let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&read, None); - let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) - .unwrap(); - let read = child(&timed); - assert_eq!(read.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(read.lifetime, Lifetime::None); - } - /// A query-time summary build cannot read ingestion-time rows that are /// not stored: at query time they no longer exist. Storing the rows node /// at ingestion time makes the same build valid (#738). @@ -1453,7 +1454,10 @@ mod tests { ); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&rows, at_ingestion()); + assignment.set( + &rows, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed = apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -1483,7 +1487,10 @@ mod tests { ); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&state, at_ingestion()); + assignment.set( + &state, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed = apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -1498,7 +1505,10 @@ mod tests { fn a_root_may_be_stored_at_ingestion_time() { let root = max(scan()); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&root, at_ingestion()); + assignment.set( + &root, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); @@ -1507,18 +1517,27 @@ mod tests { let state = agg(scan(), exact_sum()); let root = finalize(Rc::clone(&state)); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&state, at_ingestion()); - assignment.set(&root, at_ingestion()); + assignment.set( + &state, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + assignment.set( + &root, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); assert_eq!(exported(&timed, "FinalizeExactAccumulator"), KEPT_ACROSS); - let mut assignment = PhysicalPropertiesAssignment::default(); let root = placed_at_ingestion(max(scan())); - assignment.set(&root, None); assert_eq!( - apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()).err(), + apply_physical_properties( + &root, + &PhysicalPropertiesAssignment::default(), + &mut NodeToTimedNodeCache::new() + ) + .err(), Some(ExecutionDataStateError::UnstoredIngestionRoot { operator: "Aggregate" }) diff --git a/crates/types/src/physical/properties.rs b/crates/types/src/physical/properties.rs index 96ef56d09..f3cc9f658 100644 --- a/crates/types/src/physical/properties.rs +++ b/crates/types/src/physical/properties.rs @@ -39,6 +39,12 @@ impl Lifetime { pub fn is_kept(self) -> bool { self != Self::None } + + /// Whether the output is kept across evaluations: a materialized view + /// that later evaluations reuse. + pub fn is_across_evaluations(self) -> bool { + matches!(self, Self::AcrossEvaluations(_)) + } } /// A timing and a lifetime that cannot go together. @@ -50,13 +56,40 @@ pub enum InvalidPhysicalProperties { /// When a candidate runs and how long its output lives: one of the valid /// rows of the table in this module's documentation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PhysicalProperties { timing: ExecutionTiming, lifetime: Lifetime, } impl PhysicalProperties { + /// Query time, not kept: runs in each reader's execution. + pub const NOT_KEPT_AT_QUERY_TIME: Self = Self { + timing: ExecutionTiming::QueryTime, + lifetime: Lifetime::None, + }; + /// Ingestion time, not kept: runs inside the ingestion work that reads it. + pub const NOT_KEPT_AT_INGESTION: Self = Self { + timing: ExecutionTiming::IngestionTime, + lifetime: Lifetime::None, + }; + /// Query time, kept in memory until the evaluation's readers finish. + pub const KEPT_IN_MEMORY_FOR_ONE_EVALUATION: Self = Self { + timing: ExecutionTiming::QueryTime, + lifetime: Lifetime::OneEvaluation(Medium::Memory), + }; + /// Ingestion time, kept in memory until a query reads it. + pub const KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION: Self = Self { + timing: ExecutionTiming::IngestionTime, + lifetime: Lifetime::AcrossEvaluations(Medium::Memory), + }; + /// Query time, kept in memory across evaluations (a tumbling-window chain + /// that builds its newest window at each evaluation). + pub const KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME: Self = Self { + timing: ExecutionTiming::QueryTime, + lifetime: Lifetime::AcrossEvaluations(Medium::Memory), + }; + /// The properties `timing` and `lifetime`, unless they cannot go together. pub fn new( timing: ExecutionTiming, @@ -85,7 +118,7 @@ impl PhysicalProperties { reader == self.timing || (reader == ExecutionTiming::QueryTime && self.timing == ExecutionTiming::IngestionTime - && matches!(self.lifetime, Lifetime::AcrossEvaluations(_))) + && self.lifetime.is_across_evaluations()) } } @@ -119,6 +152,23 @@ mod tests { } } + /// The named properties are valid pairs. + #[test] + fn named_properties_are_valid() { + for named in [ + PhysicalProperties::NOT_KEPT_AT_QUERY_TIME, + PhysicalProperties::NOT_KEPT_AT_INGESTION, + PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + ] { + assert_eq!( + PhysicalProperties::new(named.timing(), named.lifetime()), + Ok(named) + ); + } + } + #[test] fn a_query_time_reader_reads_only_a_kept_ingestion_output() { let at = |timing, lifetime| PhysicalProperties::new(timing, lifetime).unwrap(); diff --git a/crates/types/src/physical/workload_plan.rs b/crates/types/src/physical/workload_plan.rs index 08f693bf6..97d230160 100644 --- a/crates/types/src/physical/workload_plan.rs +++ b/crates/types/src/physical/workload_plan.rs @@ -1,17 +1,13 @@ //! One evaluated physical properties assignment rebuilt as a physical DAG. -use std::collections::BTreeMap; - -use crate::ir::physical_export::{PhysicalASAPDAG, PhysicalASAPNodeId}; +use crate::ir::physical_export::PhysicalASAPDAG; use crate::ir::QueryRoot; -use super::Lifetime; - /// One CandidatePhysicalASAPDAG (Stage 2 output), derived from exactly one /// CandidateLogicalASAPDAG (Stage 1 output). It holds planning data only; /// display labels are derived from it by the devtools. #[derive(Debug, Clone)] pub struct PhysicalWorkloadPlan { - /// `P` (nothing materialized) or `P-m`, set by the caller. + /// `P` (nothing kept) or `P-m`, set by the caller. pub id: String, /// The id of the logical candidate it implements. pub from_logical: String, @@ -19,20 +15,13 @@ pub struct PhysicalWorkloadPlan { /// exports. pub roots: Vec, pub dag: PhysicalASAPDAG, - /// Its physical properties assignment: the lifetime chosen for each summary - /// build (`SummaryAgg` or `SummaryTumblingWindowChain`) of `dag`, by node id, including - /// the builds not kept (`Lifetime::None`), and each other node kept - /// (a shared node built once per evaluation). A build one query reads - /// at ingestion time and another at query time appears once per copy; - /// each copy's timing is its `dag` node's. - pub lifetime: BTreeMap, } impl PhysicalWorkloadPlan { - /// Whether any node is materialized: a summary build, or a shared + /// Whether any node of `dag` is kept: a summary build, or a shared /// non-summary node built once per evaluation. #[cfg(any(test, feature = "test-support"))] - pub fn materializes_any(&self) -> bool { - self.lifetime.values().any(|lifetime| lifetime.is_kept()) + pub fn keeps_any(&self) -> bool { + self.dag.nodes.iter().any(|node| node.lifetime.is_kept()) } } diff --git a/crates/types/tests/materialized_view.rs b/crates/types/tests/materialized_view.rs index 0ddeffe38..b438038fd 100644 --- a/crates/types/tests/materialized_view.rs +++ b/crates/types/tests/materialized_view.rs @@ -15,7 +15,6 @@ use asap_types::ir::operator::TimeShift; use asap_types::ir::physical_export::{ compile_physical_asap_dag, compile_physical_asap_workload, PhysicalASAPDAG, }; -use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::{ DataType, Field, FieldDataType, GroupingStrategy, Schema, SketchAlgorithm, SketchKind, @@ -25,7 +24,7 @@ use asap_types::ir::{ apply_physical_properties, apply_physical_properties_to_roots, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, TimeRangeKind, }; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; +use asap_types::physical::PhysicalProperties; /// A KLL of `m`'s values over `(T - shift - 1 min, T - shift]`. fn tumbling_window(scan: &Rc, shift_ms: i64) -> Rc { @@ -96,20 +95,12 @@ fn tumbling_windows_and_kept_merge() -> (PhysicalASAPDAG, usize) { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } assignment.set( &merge, - PhysicalProperties::new( - ExecutionTiming::QueryTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, ); let timed = apply_physical_properties(&merge, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); @@ -242,11 +233,7 @@ fn three_chains_over_one_scan() -> (PhysicalASAPDAG, PhysicalASAPDAG) { .map(|chain| { assignment.set( chain, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); QueryRoot::Operator( OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryMerge { @@ -384,11 +371,7 @@ fn a_shifted_tumbling_window_has_its_own_phase() { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let roots: Vec = tumbling_windows @@ -435,11 +418,7 @@ fn views_of_unbounded_windows_are_groups_of_their_own() { .unwrap(); assignment.set( &build, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); QueryRoot::Operator(build) }) @@ -472,11 +451,7 @@ fn a_view_reading_a_view_of_its_group_follows_it() { for view in [&tumbling_window, &rollup] { assignment.set( view, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let timed = @@ -529,11 +504,7 @@ fn a_view_has_its_refresh_window_on_a_dag_without_edges() { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &view, - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), + PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&view, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); diff --git a/crates/types/tests/physical_export.rs b/crates/types/tests/physical_export.rs index 4905f2844..dcbdc8c6d 100644 --- a/crates/types/tests/physical_export.rs +++ b/crates/types/tests/physical_export.rs @@ -12,7 +12,7 @@ use asap_types::ir::{ apply_physical_properties, ASAPOp, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, PhysicalPropertiesAssignment, QueryRoot, }; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; +use asap_types::physical::{InvalidPhysicalProperties, Lifetime, Medium, PhysicalProperties}; use std::rc::Rc; /// Scan(t) → SummaryAgg(sum by key) → FinalizeExactAccumulator, untimed. @@ -51,7 +51,7 @@ fn timed_at_ingestion() -> Rc { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( root.children()[0], - PhysicalProperties::new(ExecutionTiming::IngestionTime, ON_DISK).ok(), + PhysicalProperties::new(ExecutionTiming::IngestionTime, ON_DISK).unwrap(), ); apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap() } @@ -106,18 +106,13 @@ fn invalid_physical_properties_are_rejected() { dag.validate(), Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { node: 1, - timing: ExecutionTiming::IngestionTime, - lifetime: Lifetime::OneEvaluation(Medium::Disk), + reason: InvalidPhysicalProperties::OneEvaluationAtIngestion, }) ); dag.nodes[1].lifetime = Lifetime::None; assert_eq!( dag.validate(), - Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { - node: 1, - timing: ExecutionTiming::IngestionTime, - lifetime: Lifetime::None, - }) + Err(PhysicalASAPDAGValidationError::UnkeptSummaryBuildNotAtQueryTime { node: 1 }) ); dag.nodes[1].lifetime = ON_DISK; dag.validate().unwrap(); @@ -209,8 +204,7 @@ fn scalar_roots_export_in_batch_order_and_reference_nodes() { scalar_only.validate(), Err(PhysicalASAPDAGValidationError::InvalidPhysicalProperties { node: scalar_only.nodes[state].id, - timing: ExecutionTiming::IngestionTime, - lifetime: Lifetime::OneEvaluation(Medium::Disk), + reason: InvalidPhysicalProperties::OneEvaluationAtIngestion, }) ); @@ -392,13 +386,8 @@ fn exports_summary_over_summary_as_typed_precompute_edges() { })) .unwrap(); let mut cache = NodeToTimedNodeCache::new(); - let at_ingestion = PhysicalPropertiesAssignment::with_default( - PhysicalProperties::new( - ExecutionTiming::IngestionTime, - Lifetime::AcrossEvaluations(Medium::Memory), - ) - .ok(), - ); + let at_ingestion = + PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(&root)); let timed = apply_physical_properties(&root, &at_ingestion, &mut cache).unwrap(); let compiled = compile_physical_asap_dag_with_node_ids(&timed).unwrap(); assert_eq!(compiled.node_ids.node_id(&timed), Some(3)); @@ -522,7 +511,7 @@ fn every_node_at_query_time_keeps_the_operators_and_stores_nothing() { ]) .unwrap() }; - let materialized = workload(timed_at_ingestion()); + let kept = workload(timed_at_ingestion()); let at_query_time = apply_physical_properties( &plan(), &PhysicalPropertiesAssignment::default(), @@ -530,7 +519,7 @@ fn every_node_at_query_time_keeps_the_operators_and_stores_nothing() { ) .unwrap(); assert_eq!( - materialized.with_every_node_at_query_time().unwrap(), + kept.with_every_node_at_query_time().unwrap(), workload(at_query_time) ); } diff --git a/crates/types/tests/schema_rebuilding.rs b/crates/types/tests/schema_rebuilding.rs index ce0a60163..80282540f 100644 --- a/crates/types/tests/schema_rebuilding.rs +++ b/crates/types/tests/schema_rebuilding.rs @@ -354,7 +354,7 @@ fn population_timing_follows_its_physical_properties() { let mut at_ingestion = PhysicalPropertiesAssignment::default(); at_ingestion.set( population, - PhysicalProperties::new(IngestionTime, on_disk).ok(), + PhysicalProperties::new(IngestionTime, on_disk).unwrap(), ); for (assignment, timing, lifetime) in [ ( diff --git a/crates/types/tests/summary_merge_structure.rs b/crates/types/tests/summary_merge_structure.rs index 773fa16bd..0a6adbf7c 100644 --- a/crates/types/tests/summary_merge_structure.rs +++ b/crates/types/tests/summary_merge_structure.rs @@ -13,7 +13,7 @@ use asap_types::ir::{ apply_physical_properties, ASAPOp, ExprSemantics, NodeToTimedNodeCache, NonASAPOp, Operator, OperatorNode, PhysicalPropertiesAssignment, Predicate, ScalarExpr, }; -use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; +use asap_types::physical::PhysicalProperties; use std::rc::Rc; /// KLL over `value` for one `region`, so states of different regions are /// disjoint. @@ -719,8 +719,7 @@ fn summary_merge_timing() { timings(&PhysicalPropertiesAssignment::default()), (QueryTime, vec![QueryTime, QueryTime]) ); - let at_ingestion = - PhysicalProperties::new(IngestionTime, Lifetime::AcrossEvaluations(Medium::Memory)).ok(); + let at_ingestion = PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION; let mut stored_tumbling_windows = PhysicalPropertiesAssignment::default(); for tumbling_window in &tumbling_windows { stored_tumbling_windows.set(tumbling_window, at_ingestion); @@ -736,7 +735,8 @@ fn summary_merge_timing() { assert!( apply_physical_properties(&root, &only_merge, &mut NodeToTimedNodeCache::new()).is_err() ); - let mut stored_merge = PhysicalPropertiesAssignment::with_default(at_ingestion); + let mut stored_merge = + PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(&root)); stored_merge.set(&root, at_ingestion); assert_eq!( timings(&stored_merge), diff --git a/crates/types/tests/tumbling_window_chain.rs b/crates/types/tests/tumbling_window_chain.rs index dd5a89251..b218de6a2 100644 --- a/crates/types/tests/tumbling_window_chain.rs +++ b/crates/types/tests/tumbling_window_chain.rs @@ -198,12 +198,9 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { })) .unwrap(); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set( - &chain, - lifetime - .is_kept() - .then(|| PhysicalProperties::new(timing, lifetime).unwrap()), - ); + if lifetime.is_kept() { + assignment.set(&chain, PhysicalProperties::new(timing, lifetime).unwrap()); + } let timed = apply_physical_properties(&estimate, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); diff --git a/docs/design_docs/concepts/post-asap-ir.md b/docs/design_docs/concepts/post-asap-ir.md index 6e385b356..1b4964c95 100644 --- a/docs/design_docs/concepts/post-asap-ir.md +++ b/docs/design_docs/concepts/post-asap-ir.md @@ -158,14 +158,14 @@ node reached from two consumers that need different timings; assignment is applied. How much a kept output retains (retention) is decided later and is not in the assignment. -`PhysicalPropertiesAssignment::with_default(kept)` gives every sub-DAG that is -not set explicitly `kept` where the DAG allows it; an ingestion-time default -over a sub-DAG that can only run at query time leaves that sub-DAG not kept -instead of failing (the default applies to -`SummaryAgg` and `MaintainPopulation` nodes). The test helpers `validate_at_ingestion` and -`planned_data_state` (feature `test-support`) use it to check, at planning time and without keeping -anything, that a candidate stays valid when every sub-DAG is kept at ingestion -time. +A node the assignment does not set is not kept. The test helper +`PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(roots)` +(feature `test-support`) sets every `SummaryAgg`, `SummaryTumblingWindowChain` +and `MaintainPopulation` kept at ingestion time where the DAG allows it (not +filtered, nothing below it that can only run at query time). The test +helpers `validate_at_ingestion` and `planned_data_state` use it to check, at +planning time and without keeping anything, that a candidate stays valid +when every sub-DAG is kept at ingestion time. ## Exported DAG diff --git a/docs/design_docs/physical-planning-and-deployment.md b/docs/design_docs/physical-planning-and-deployment.md index fa3a47360..1a1299b3b 100644 --- a/docs/design_docs/physical-planning-and-deployment.md +++ b/docs/design_docs/physical-planning-and-deployment.md @@ -744,7 +744,7 @@ operator/runtime fixtures: | `kll_tumbling_window_execution::a_store_keyed_by_definition_and_time_range_answers_the_tumbling_windows` | A store that finds states only by `(definition_id, time range)` answers the five-tumbling-window query: the tumbling windows share one definition and request the five ranges that tile the window | | `runtime_install::tumbling_windows_of_one_refresh_window_read_each_raw_window_once` | A KLL chain and a DDSketch chain of 10 s tumbling windows over one `Scan` are one refresh group: each tumbling window window is read from raw data once, in one ingestion run that builds both tumbling windows; each state equals that of a run of its view alone, and both queries answer as the query-time reference | | `kll_tumbling_window_execution::tumbling_windows_reject_parameters_schema_and_missing_binding` | Parameter relabelling, incompatible schemas and missing views fail explicitly | -| `precompute_candidates::grouped_rate_can_be_materialized_before_or_after_grouped_sum` | Stored Rate state and stored Sum state answer like query time; summing counters before Rate does not | +| `precompute_candidates::grouped_rate_can_be_kept_before_or_after_grouped_sum` | Stored Rate state and stored Sum state answer like query time; summing counters before Rate does not | | `sql_to_physical::sql_filter_grouped_sum_executes_and_rebinds` | SQL text → candidate search → physical compilation → shared Scan predicates and grouped summary execution; NULL samples are ignored and fresh bindings produce new results | Tumbling window construction, tumbling window timestamp checks, stored identity, revisions, readiness diff --git a/docs/design_docs/proposals/planner-layering-example4-acceptance.md b/docs/design_docs/proposals/planner-layering-example4-acceptance.md index 54b5e003e..724e1058f 100644 --- a/docs/design_docs/proposals/planner-layering-example4-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example4-acceptance.md @@ -80,7 +80,7 @@ it. |---|---|---| | Every node upstream of an ingestion-time node also runs at ingestion time (all variants) | `stage2_physical_asap_optimization_ingestion_time_upstream_is_ingestion_time`; the monthly variant in `stage2_physical_asap_optimization_monthly_ingestion_time_upstream_is_ingestion_time` | passes: B1 and the monthly variant's maintained tumbling windows; the monthly test is ignored as slow (run in release by hand) | | With data at rest, no node runs at ingestion time | `stage2_physical_asap_optimization_at_rest_runs_nothing_at_ingestion_time` | passes | -| A materialized output covers its consumers: retention ≥ max over its readers of `lookback` + offset | `stage2_physical_asap_optimization_materialized_output_covers_its_consumers`; the monthly variant in `stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers` | passes: B1 keeps 6 min ≥ 5 min; the monthly test is ignored as slow (run in release by hand) | +| A materialized output covers its consumers: retention ≥ max over its readers of `lookback` + offset | `stage2_physical_asap_optimization_kept_output_covers_its_consumers`; the monthly variant in `stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers` | passes: B1 keeps 6 min ≥ 5 min; the monthly test is ignored as slow (run in release by hand) | ### Pattern A @@ -88,7 +88,7 @@ it. |---|---|---| | The shared EH yields exactly A1, A2, A3 | `stage2_physical_asap_optimization_a_shared_eh_has_three_materialization_options` | ignored: the shared EH (#628, #634) | | At rest, A2 is not generated; A1 and A3 remain | `stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option` | ignored: the shared EH (#628, #634) | -| A materialized EH is one build node read by all five queries, priced once | `stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers` | ignored: the shared EH (#628, #634) | +| A materialized EH is one build node read by all five queries, priced once | `stage2_physical_asap_optimization_a_kept_eh_is_built_once_for_all_consumers` | ignored: the shared EH (#628, #634) | | A3 costs strictly more than A1 (five builds instead of one: a `Lifetime::None` node is charged per consuming query) | `stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once` | ignored: the shared EH (#628, #634) | | As given, A1 is the cheapest of the three | `stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh` | ignored: the shared EH (#628, #634) | | Monthly, A2's cost relative to A1 drops: cost(A2)/cost(A1) monthly < as given | `stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance` | ignored: the shared EH (#628, #634) | From c289f9571892358eee11f7bb2fa6db20e1b2771d Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 01:06:05 +0000 Subject: [PATCH 5/9] build: logical-asap-optimization's test-support enables asap-types' test-support test_support::at_ingestion calls the test-support builder PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed, so a crate built alone with logical-asap-optimization/test-support (e.g. cargo test -p asap-cost) needs asap-types' test-support too. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/logical-asap-optimization/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/logical-asap-optimization/Cargo.toml b/crates/logical-asap-optimization/Cargo.toml index 665246936..3154d7233 100644 --- a/crates/logical-asap-optimization/Cargo.toml +++ b/crates/logical-asap-optimization/Cargo.toml @@ -21,7 +21,7 @@ asap-frontend-promql = { path = "../frontend-promql", optional = true } [features] # The test helpers (`test_support`) the later stage crates' tests share. -test-support = ["dep:asap-frontend-promql"] +test-support = ["dep:asap-frontend-promql", "asap-types/test-support"] [dev-dependencies] asap-types = { path = "../types", features = ["test-support"] } From 24b894fa99d997dd4bd1b7e41381084419bb8ecf Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 03:39:44 +0000 Subject: [PATCH 6/9] fix: an invalid timed node reports its error instead of reading as untimed OperatorNode::physical_properties returns Option>: None before timing, Err when timing and lifetime cannot go together. The timing pass reports ExecutionDataStateError::InvalidPhysicalProperties, and execution_demand::computations returns AnalyticalCostError::InvalidPhysicalProperties instead of skipping the node. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/src/analytical.rs | 3 ++ crates/cost/src/execution_demand.rs | 19 ++++---- crates/cost/tests/ingestion_refresh_runs.rs | 26 ++++++++++ crates/planner/tests/runtime_install.rs | 2 +- crates/types/src/ir/operator/node.rs | 10 ++-- .../src/ir/properties/execution_data_state.rs | 10 +++- crates/types/src/ir/properties/timing.rs | 48 +++++++++++++++---- 7 files changed, 93 insertions(+), 25 deletions(-) diff --git a/crates/cost/src/analytical.rs b/crates/cost/src/analytical.rs index 6c6640a18..a835fff4a 100644 --- a/crates/cost/src/analytical.rs +++ b/crates/cost/src/analytical.rs @@ -1489,6 +1489,9 @@ pub enum AnalyticalCostError { UnsupportedWithoutDistribution(&'static str), #[error("analytical arithmetic overflowed")] Overflow, + /// A node whose timing and lifetime cannot go together: a planner bug. + #[error("{0}")] + InvalidPhysicalProperties(asap_types::physical::InvalidPhysicalProperties), #[error("candidate has no supported exact or sketch state")] UnsupportedCandidate, #[error("inconsistent operator statistics: {0}")] diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index 9c12d997e..9c8ac8cb1 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -359,16 +359,15 @@ pub fn computations( root_rates: Option<&[f64]>, ) -> Result, AnalyticalCostError> { let range_of = |query: usize| range_evaluations.get(query).copied().flatten(); - let kept_nodes: HashMap = dag - .nodes - .iter() - .filter_map(|n| { - n.physical_properties() - .ok() - .filter(|p| p.lifetime().is_kept()) - .map(|p| (n.id, p)) - }) - .collect(); + let mut kept_nodes: HashMap = HashMap::new(); + for node in &dag.nodes { + let properties = node + .physical_properties() + .map_err(AnalyticalCostError::InvalidPhysicalProperties)?; + if properties.lifetime().is_kept() { + kept_nodes.insert(node.id, properties); + } + } let inputs = |id: PhysicalASAPNodeId| { dag.edges .iter() diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index 182e5effd..b57a36685 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -285,3 +285,29 @@ fn consumers_of_unbounded_windows_count_alone() { (2, 2.0) ); } + +/// A node whose timing and lifetime cannot go together (kept for one +/// evaluation at ingestion time) is reported, not skipped. +#[test] +fn an_invalid_node_is_reported_not_skipped() { + let scan = scan(); + let mut dag = dag_of( + &[chain(&scan, SketchAlgorithm::Kll, 10_000, 6)], + Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + ); + let chain = dag + .nodes + .iter_mut() + .find(|node| node.lifetime.is_kept()) + .unwrap(); + chain.lifetime = + asap_types::physical::Lifetime::OneEvaluation(asap_types::physical::Medium::Memory); + assert!(matches!( + computations(&dag, &[], &[], 3600.0, None), + Err( + asap_cost::analytical::AnalyticalCostError::InvalidPhysicalProperties( + asap_types::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion + ) + ) + )); +} diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index 0adf208f3..70250d0aa 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -1576,7 +1576,7 @@ fn untime( ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } | ASAPOp::SummaryMerge { .. }, - ) if node.lifetime.is_kept() => node.physical_properties(), + ) if node.lifetime.is_kept() => node.physical_properties().map(Result::unwrap), _ => None, }; if let Some(kept) = store(node).or(own) { diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index b02f70ae4..d4c8e41a4 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -15,7 +15,7 @@ use crate::ir::properties::guarantee::AccuracyGuarantee; use crate::ir::properties::summary_coverage::{NodeToSummaryCoverageCache, SummaryCoverage}; use crate::ir::schema::Schema; use crate::ir::SchemaDerivationError; -use crate::physical::{Lifetime, PhysicalProperties}; +use crate::physical::{InvalidPhysicalProperties, Lifetime, PhysicalProperties}; /// The output category of an operator, derived from the operation and its /// inputs. Matching column schemas do not make categories interchangeable. @@ -108,9 +108,11 @@ pub struct OperatorNode { impl OperatorNode { /// Its timing and lifetime, once [`crate::ir::apply_physical_properties`] - /// has timed it; `None` before. - pub fn physical_properties(&self) -> Option { - PhysicalProperties::new(self.timing?, self.lifetime).ok() + /// has timed it (`None` before), or why they cannot go together. + pub fn physical_properties( + &self, + ) -> Option> { + Some(PhysicalProperties::new(self.timing?, self.lifetime)) } /// Build a node, deriving its schema and output category. Fails when the diff --git a/crates/types/src/ir/properties/execution_data_state.rs b/crates/types/src/ir/properties/execution_data_state.rs index 35f421ba3..f7f52ffc4 100644 --- a/crates/types/src/ir/properties/execution_data_state.rs +++ b/crates/types/src/ir/properties/execution_data_state.rs @@ -10,7 +10,7 @@ use thiserror::Error; -use crate::physical::PhysicalProperties; +use crate::physical::{InvalidPhysicalProperties, PhysicalProperties}; /// When a post-ASAP value is produced. #[derive( @@ -155,6 +155,14 @@ pub enum ExecutionDataStateError { fixed: ExecutionTiming, assigned: PhysicalProperties, }, + /// A timed node whose timing and lifetime cannot go together: a bug in + /// whatever built the node. + #[error("{operator} node: {reason}")] + InvalidPhysicalProperties { + operator: &'static str, + #[source] + reason: InvalidPhysicalProperties, + }, /// A summary build with a filter placed at ingestion time. An /// ingestion-time build reads raw data samples, which carry none of the /// query's columns the filter reads, so only a query-time build can diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index c487d27c6..58e6a53cf 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -189,6 +189,19 @@ impl PhysicalPropertiesAssignment { } } +/// `node`'s physical properties once timed (`None` before), or its error +/// when its timing and lifetime cannot go together. +fn timed_properties( + node: &OperatorNode, +) -> Result, ExecutionDataStateError> { + node.physical_properties().transpose().map_err(|reason| { + ExecutionDataStateError::InvalidPhysicalProperties { + operator: node.operator.kind_name(), + reason, + } + }) +} + /// Whether `operator`'s output is a sub-DAG output that materialization may /// store: a `SummaryAgg`, a `SummaryTumblingWindowChain` or a `MaintainPopulation`. pub(crate) fn is_keepable_state_output(operator: &Operator) -> bool { @@ -330,9 +343,7 @@ pub fn apply_physical_properties( // A root stored at ingestion time is read by the query; one that runs at // ingestion time without being stored there produces rows nothing reads. if timed.timing == Some(ExecutionTiming::IngestionTime) - && !timed - .physical_properties() - .is_some_and(|p| p.readable_at(ExecutionTiming::QueryTime)) + && !timed_properties(&timed)?.is_some_and(|p| p.readable_at(ExecutionTiming::QueryTime)) && data_state(&timed).map(|s| s.primitive) == Some(DataPrimitive::Raw) { return Err(ExecutionDataStateError::UnstoredIngestionRoot { @@ -613,9 +624,7 @@ fn validate_asap( // `NonASAP` consumer does. if timing == ExecutionTiming::QueryTime && avail.timing == ExecutionTiming::IngestionTime - && !child - .physical_properties() - .is_some_and(|p| p.readable_at(timing)) + && !timed_properties(child)?.is_some_and(|p| p.readable_at(timing)) { return Err( ExecutionDataStateError::UnstoredIngestionInputUnderQueryTimeSummary { @@ -766,9 +775,7 @@ fn validate_non_asap( && (is_exact_accumulator_state(&child.schema).is_ok() || selects_states(node)); // A query-time consumer may read the stored output of a sub-DAG // materialized at ingestion time. - let reads_stored = child - .physical_properties() - .is_some_and(|p| p.readable_at(timing)); + let reads_stored = timed_properties(child)?.is_some_and(|p| p.readable_at(timing)); if (s.timing != timing && !reads_stored) || (s.primitive != DataPrimitive::Raw && !passes_state) { @@ -1498,6 +1505,29 @@ mod tests { assert_eq!(child(&timed).lifetime, KEPT_ACROSS); } + /// A node placed at ingestion time with a lifetime that cannot go with + /// it reports that, not "not stored". + #[test] + fn an_invalid_timed_node_reports_its_error() { + let root = Rc::new( + (*placed_at_ingestion(max(scan()))) + .clone() + .with_lifetime(Lifetime::OneEvaluation(Medium::Memory)), + ); + assert_eq!( + apply_physical_properties( + &root, + &PhysicalPropertiesAssignment::default(), + &mut NodeToTimedNodeCache::new() + ) + .err(), + Some(ExecutionDataStateError::InvalidPhysicalProperties { + operator: "Aggregate", + reason: crate::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion, + }) + ); + } + /// A root stored at ingestion time is valid: the query reads the stored /// output. A root that runs at ingestion time without being stored there /// is not. From 0f9cb9406a58e5c1dbc7fc373b7a05542354156b Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 14:46:02 +0000 Subject: [PATCH 7/9] fix: AnalyticalCostError::InvalidPhysicalProperties names the node; test both timing-pass call sites AnalyticalCostError::InvalidPhysicalProperties becomes { node, reason }, so a costing error names the node whose timing and lifetime cannot go together. New timing-pass tests cover the validate_asap and validate_non_asap call sites of ExecutionDataStateError::InvalidPhysicalProperties. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/src/analytical.rs | 8 +++- crates/cost/src/execution_demand.rs | 9 ++-- crates/cost/tests/ingestion_refresh_runs.rs | 12 +++--- crates/types/src/ir/properties/timing.rs | 48 +++++++++++++++++++++ 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/crates/cost/src/analytical.rs b/crates/cost/src/analytical.rs index a835fff4a..dd136576f 100644 --- a/crates/cost/src/analytical.rs +++ b/crates/cost/src/analytical.rs @@ -1490,8 +1490,12 @@ pub enum AnalyticalCostError { #[error("analytical arithmetic overflowed")] Overflow, /// A node whose timing and lifetime cannot go together: a planner bug. - #[error("{0}")] - InvalidPhysicalProperties(asap_types::physical::InvalidPhysicalProperties), + #[error("node {node:?}: {reason}")] + InvalidPhysicalProperties { + node: asap_types::ir::physical_export::PhysicalASAPNodeId, + #[source] + reason: asap_types::physical::InvalidPhysicalProperties, + }, #[error("candidate has no supported exact or sketch state")] UnsupportedCandidate, #[error("inconsistent operator statistics: {0}")] diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index 9c8ac8cb1..9e417f94f 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -361,9 +361,12 @@ pub fn computations( let range_of = |query: usize| range_evaluations.get(query).copied().flatten(); let mut kept_nodes: HashMap = HashMap::new(); for node in &dag.nodes { - let properties = node - .physical_properties() - .map_err(AnalyticalCostError::InvalidPhysicalProperties)?; + let properties = node.physical_properties().map_err(|reason| { + AnalyticalCostError::InvalidPhysicalProperties { + node: node.id, + reason, + } + })?; if properties.lifetime().is_kept() { kept_nodes.insert(node.id, properties); } diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index b57a36685..408fc141e 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -302,12 +302,14 @@ fn an_invalid_node_is_reported_not_skipped() { .unwrap(); chain.lifetime = asap_types::physical::Lifetime::OneEvaluation(asap_types::physical::Medium::Memory); - assert!(matches!( + let chain = chain.id; + assert_eq!( computations(&dag, &[], &[], 3600.0, None), Err( - asap_cost::analytical::AnalyticalCostError::InvalidPhysicalProperties( - asap_types::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion - ) + asap_cost::analytical::AnalyticalCostError::InvalidPhysicalProperties { + node: chain, + reason: asap_types::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion, + } ) - )); + ); } diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index 58e6a53cf..21ca9813a 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -1528,6 +1528,54 @@ mod tests { ); } + /// `node` fixed at ingestion time with a lifetime that cannot go with it. + fn invalid_at_ingestion(node: Rc) -> Rc { + Rc::new( + (*placed_at_ingestion(node)) + .clone() + .with_lifetime(Lifetime::OneEvaluation(Medium::Memory)), + ) + } + + /// A query-time summary build whose ingestion-time input has an invalid + /// timing and lifetime reports that (`validate_asap`), not "not stored". + #[test] + fn a_summary_build_over_an_invalid_input_reports_its_error() { + let root = agg(invalid_at_ingestion(scan()), exact_sum()); + assert_eq!( + apply_physical_properties( + &root, + &PhysicalPropertiesAssignment::default(), + &mut NodeToTimedNodeCache::new() + ) + .err(), + Some(ExecutionDataStateError::InvalidPhysicalProperties { + operator: "Scan", + reason: crate::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion, + }) + ); + } + + /// A query-time `NonASAP` node whose ingestion-time input has an invalid + /// timing and lifetime reports that (`validate_non_asap`), not an illegal + /// child data state. + #[test] + fn a_non_asap_node_over_an_invalid_input_reports_its_error() { + let root = max(invalid_at_ingestion(max(scan()))); + assert_eq!( + apply_physical_properties( + &root, + &PhysicalPropertiesAssignment::default(), + &mut NodeToTimedNodeCache::new() + ) + .err(), + Some(ExecutionDataStateError::InvalidPhysicalProperties { + operator: "Aggregate", + reason: crate::physical::InvalidPhysicalProperties::OneEvaluationAtIngestion, + }) + ); + } + /// A root stored at ingestion time is valid: the query reads the stored /// output. A root that runs at ingestion time without being stored there /// is not. From a225368b3a9fca48016059b45f506fb6d2e040c8 Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 15:16:50 +0000 Subject: [PATCH 8/9] refactor: say materialized, not kept, for lifetime other than None The formulation (#1200) calls l != None materialized. Every name this PR introduced with 'kept' says 'materialized': Lifetime::is_materialized, MaterializedOutputCandidate, find_materialized_output_candidates, SummaryMaterializationEligibility, materialized_at_ingestion_where_allowed, materializes_any, materialized_tumbling_window_chains, PhysicalProperties::MATERIALIZED_IN_MEMORY_* and NOT_MATERIALIZED_AT_*, Consumer::Materialized, and the tests and doc comments. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/src/execution_demand.rs | 46 +-- crates/cost/src/lib.rs | 6 +- crates/cost/src/usage.rs | 30 +- crates/cost/tests/held_memory.rs | 16 +- crates/cost/tests/ingestion_refresh_runs.rs | 22 +- crates/devtools/src/candidate_labels.rs | 2 +- crates/devtools/tests/asap_planner.rs | 2 +- crates/executor/src/physical_planner/mod.rs | 2 +- .../executor/tests/precompute_candidates.rs | 2 +- .../executor/tests/precompute_population.rs | 2 +- .../executor/tests/weighted_topk_binding.rs | 6 +- crates/integration-tests/src/lib.rs | 12 +- .../tests/materialized_views.rs | 4 +- .../tests/physical_common/mod.rs | 4 +- .../tests/physical_properties_e2e.rs | 22 +- .../tests/planner_layering_common/mod.rs | 64 ++-- .../tests/planner_layering_example1.rs | 36 +- .../tests/planner_layering_example2.rs | 2 +- .../tests/planner_layering_example4.rs | 78 +++-- .../tests/production_rollup_workloads.rs | 4 +- .../tests/range_evaluation.rs | 2 +- .../tests/rollup_controlled.rs | 2 +- .../tests/runtime_handoff.rs | 13 +- .../tests/sharing_issue_regressions.rs | 2 +- .../tests/tumbling_window_merge.rs | 8 +- .../src/pass1/per_computation_candidates.rs | 2 +- .../rules/shared_configuration_readers.rs | 2 +- .../src/test_support.rs | 8 +- .../src/catalog/configurations.rs | 54 +-- .../src/catalog/inventory.rs | 2 +- .../src/catalog/realize.rs | 28 +- crates/physical-asap-optimization/src/lib.rs | 330 +++++++++++------- .../src/split_by_timing.rs | 27 +- crates/plan-selection/src/groups.rs | 8 +- crates/plan-selection/src/groups/tests.rs | 22 +- crates/plan-selection/src/lib.rs | 59 ++-- crates/plan-selection/src/milp/decode.rs | 4 +- crates/plan-selection/src/milp/model/tests.rs | 16 +- crates/plan-selection/src/select.rs | 4 +- crates/plan-selection/src/selector.rs | 11 +- crates/planner/src/installable.rs | 4 +- .../tests/deployment_accuracy_model.rs | 2 +- crates/planner/tests/per_sample_updater.rs | 2 +- crates/planner/tests/runtime_install.rs | 8 +- crates/planner/tests/summary_sharing.rs | 4 +- crates/types/src/ir/materialized_view.rs | 4 +- crates/types/src/ir/operator/node.rs | 2 +- crates/types/src/ir/physical_export.rs | 34 +- .../src/ir/properties/execution_data_state.rs | 8 +- crates/types/src/ir/properties/timing.rs | 151 ++++---- crates/types/src/physical/properties.rs | 42 +-- crates/types/src/physical/workload_plan.rs | 11 +- .../src/stages/physical/memo_candidates.rs | 4 +- crates/types/tests/materialized_view.rs | 14 +- crates/types/tests/physical_export.rs | 11 +- crates/types/tests/schema_rebuilding.rs | 2 +- crates/types/tests/summary_merge_structure.rs | 7 +- crates/types/tests/tumbling_window_chain.rs | 8 +- .../architecture/physical-plan-integration.md | 2 +- .../architecture/planner-runtime-contract.md | 2 +- docs/design_docs/concepts/glossary.md | 2 +- docs/design_docs/concepts/post-asap-ir.md | 40 +-- .../physical-planning-and-deployment.md | 8 +- .../planner-layering-example2-acceptance.md | 6 +- .../planner-layering-example4-acceptance.md | 6 +- .../design_docs/proposals/planner-layering.md | 16 +- .../asap-aware-mapping-architecture.md | 4 +- .../asap-aware-mapping-contracts.md | 10 +- .../develop_docs/extend-asap-aware-mapping.md | 2 +- ...ng-window-search-compression-evaluation.md | 2 +- 70 files changed, 759 insertions(+), 625 deletions(-) diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index 9e417f94f..c902ef3a7 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -281,29 +281,29 @@ pub fn query_starts(dag: &PhysicalASAPDAG) -> Vec> { .collect() } -/// What computes a not-kept node once per its own execution +/// What computes a not-materialized node once per its own execution /// ([`consumers`]). #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Consumer { /// Query `.0` (an operator or scalar root), at its own rate. Query(usize), - /// A kept node, at that node's rate. - Kept(PhysicalASAPNodeId), + /// A materialized node, at that node's rate. + Materialized(PhysicalASAPNodeId), } -/// The consumers of each not-kept node of `dag` that any consumer +/// The consumers of each not-materialized node of `dag` that any consumer /// reaches ([`computations`]): the queries and the materialized nodes whose /// walk down their inputs reaches it before meeting a materialized node, /// each once; the queries first, in order, then the materialized nodes in /// `dag`'s node order. pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap> { - let kept_nodes: Vec = dag + let materialized_nodes: Vec = dag .nodes .iter() - .filter(|n| n.lifetime.is_kept()) + .filter(|n| n.lifetime.is_materialized()) .map(|n| n.id) .collect(); - let is_kept: HashSet = kept_nodes.iter().copied().collect(); + let is_materialized: HashSet = materialized_nodes.iter().copied().collect(); let inputs = |id: PhysicalASAPNodeId| { dag.edges .iter() @@ -315,16 +315,16 @@ pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap> = HashMap::new(); for (consumer, start) in walks { let mut seen = HashSet::new(); let mut stack: Vec = start; while let Some(id) = stack.pop() { - if is_kept.contains(&id) || !seen.insert(id) { + if is_materialized.contains(&id) || !seen.insert(id) { continue; } consumers.entry(id).or_default().push(consumer); @@ -336,17 +336,17 @@ pub fn consumers(dag: &PhysicalASAPDAG) -> HashMap, ) -> Result, AnalyticalCostError> { let range_of = |query: usize| range_evaluations.get(query).copied().flatten(); - let mut kept_nodes: HashMap = HashMap::new(); + let mut materialized_nodes: HashMap = HashMap::new(); for node in &dag.nodes { let properties = node.physical_properties().map_err(|reason| { AnalyticalCostError::InvalidPhysicalProperties { @@ -367,8 +367,8 @@ pub fn computations( reason, } })?; - if properties.lifetime().is_kept() { - kept_nodes.insert(node.id, properties); + if properties.lifetime().is_materialized() { + materialized_nodes.insert(node.id, properties); } } let inputs = |id: PhysicalASAPNodeId| { @@ -391,8 +391,8 @@ pub fn computations( stack.extend(inputs(id)); } } - let mut rate_of_kept = HashMap::new(); - for (&id, &properties) in &kept_nodes { + let mut rate_of_materialized = HashMap::new(); + for (&id, &properties) in &materialized_nodes { let at_ingestion = properties.timing() == ExecutionTiming::IngestionTime; // A query-time chain kept across evaluations is built once per request. let per_request = !at_ingestion && properties.lifetime().is_across_evaluations(); @@ -406,7 +406,7 @@ pub fn computations( non_repeating_query_horizon_seconds, )?, }; - rate_of_kept.insert(id, rate); + rate_of_materialized.insert(id, rate); } // Each query consumer's rate. let mut query_rates = Vec::new(); @@ -421,7 +421,7 @@ pub fn computations( } // The refresh window of each node refreshed at ingestion. let refresh_windows = dag.refresh_windows( - kept_nodes + materialized_nodes .iter() .filter(|(_, properties)| properties.timing() == ExecutionTiming::IngestionTime) .map(|(&id, _)| id), @@ -432,7 +432,7 @@ pub fn computations( // The refresh windows whose ingestion run already computes the node. let mut runs = HashSet::new(); for consumer in of_node { - if let Consumer::Kept(node) = consumer { + if let Consumer::Materialized(node) = consumer { if let Some(Some(window)) = refresh_windows.get(&node) { if !runs.insert(*window) { continue; @@ -442,7 +442,7 @@ pub fn computations( entry.0 += 1; entry.1 += match consumer { Consumer::Query(query) => query_rates[query], - Consumer::Kept(node) => rate_of_kept[&node], + Consumer::Materialized(node) => rate_of_materialized[&node], }; } } @@ -450,7 +450,7 @@ pub fn computations( .nodes .iter() .map(|n| { - let times = match rate_of_kept.get(&n.id) { + let times = match rate_of_materialized.get(&n.id) { Some(&rate) => (1, rate), None => count.get(&n.id).copied().unwrap_or((0, 0.0)), }; diff --git a/crates/cost/src/lib.rs b/crates/cost/src/lib.rs index 3dc4bac35..f921d3bb7 100644 --- a/crates/cost/src/lib.rs +++ b/crates/cost/src/lib.rs @@ -41,7 +41,7 @@ pub use measured::{ pub use operator_statistics::EdgeStatistics; pub use ranking::{cheaper, worst_latency_ms, PlanRanking}; pub use usage::{ - family_name, kept_tumbling_window_chains, maintained_window_ms, node_map, node_usage, + family_name, maintained_window_ms, materialized_tumbling_window_chains, node_map, node_usage, plan_cost, query_reach, retained_tumbling_windows, trailing_window, tumbling_window_retention_ms, tumbling_window_retention_ms_of_plan, tumbling_windows_of, NodeMap, NodeUsage, ProducerOutput, @@ -80,7 +80,7 @@ pub struct ResourceUsage { pub average_memory_bytes: f64, /// The most memory live at once, assuming every evaluation overlaps: /// in-memory kept state plus each computation's working memory, once - /// per consumer that recomputes it, with the consumers kept at ingestion time + /// per consumer that recomputes it, with the consumers materialized at ingestion time /// of one refresh window counted once. pub peak_memory_bytes: u64, /// Bytes kept on disk: state materialized on `Medium::Disk`, plus the @@ -375,7 +375,7 @@ pub struct NodeCost { /// node the query reads first. pub cpu_core_seconds_per_second: f64, /// The number of consumers it is computed for, with the - /// consumers kept at ingestion time of one refresh window counted once (1 + /// consumers materialized at ingestion time of one refresh window counted once (1 /// when materialized, [`execution_demand::computations`]). pub multiplier: u64, /// How it was measured, e.g. "scan 1000 samples; x 1.0000/s; keeps diff --git a/crates/cost/src/usage.rs b/crates/cost/src/usage.rs index a74d2ddf1..e4c6e98d8 100644 --- a/crates/cost/src/usage.rs +++ b/crates/cost/src/usage.rs @@ -46,15 +46,15 @@ use asap_types::workload::bounds::{ /// ([`computations`]); an ingestion-time node over one second of arriving /// rows. A materialized node's kept state is counted in byte-seconds per /// second; a tumbling-window chain kept beyond one evaluation keeps the tumbling windows its -/// retention covers ([`tumbling_window_retention_ms`]). `nodes` and `kept_chains` are -/// `dag`'s ([`node_map`], [`kept_tumbling_window_chains`]); `recurrence[q]` and +/// retention covers ([`tumbling_window_retention_ms`]). `nodes` and `materialized_chains` are +/// `dag`'s ([`node_map`], [`materialized_tumbling_window_chains`]); `recurrence[q]` and /// `range_evaluations[q]` say how often query `q` runs and how many steps /// each run evaluates (one when missing). #[allow(clippy::too_many_arguments)] pub fn plan_cost( dag: &PhysicalASAPDAG, nodes: &NodeMap<'_>, - kept_chains: &HashSet, + materialized_chains: &HashSet, recurrence: &[QueryRecurrence], range_evaluations: &[Option], data: &DataWorkload, @@ -77,7 +77,7 @@ pub fn plan_cost( } = each_node_usage( dag, nodes, - kept_chains, + materialized_chains, recurrence, range_evaluations, data, @@ -95,7 +95,7 @@ pub fn plan_cost( // one second of arriving rows at ingestion time. let mut work_ms: HashMap = HashMap::new(); // Query-time memory held only while one evaluation runs, a OneEvaluation - // state in memory or a not-kept node's working memory: (bytes, + // state in memory or a not-materialized node's working memory: (bytes, // per second, whether each consumer computes its own copy), // counted once the evaluations' latencies are known, in node order so // the sum is the same in every run. @@ -248,7 +248,7 @@ pub fn plan_cost( } // Query-time memory is held for one evaluation: a `OneEvaluation` state from // its build until the longest query reading it finishes, about that - // query's latency, once per execution. A not-kept node's working + // query's latency, once per execution. A not-materialized node's working // memory is computed once per consumer ([`consumers`]), and each copy is // held while its consumer's evaluation runs: a query's for that query's // latency, at its rate; a materialized node's until the longest query @@ -282,7 +282,9 @@ pub fn plan_cost( .map_err(|error| (id, error))?; rate * latency.get(query).map_or(0.0, QueryLatency::total_ms) } - Consumer::Kept(node) => multipliers[&node].1 * longest_reader_ms(node), + Consumer::Materialized(node) => { + multipliers[&node].1 * longest_reader_ms(node) + } }; } sum @@ -377,7 +379,7 @@ struct EachNodeUsage<'a> { fn each_node_usage<'a>( dag: &'a PhysicalASAPDAG, nodes: &NodeMap<'a>, - kept_chains: &HashSet, + materialized_chains: &HashSet, recurrence: &[QueryRecurrence], range_evaluations: &[Option], data: &DataWorkload, @@ -421,11 +423,11 @@ fn each_node_usage<'a>( .collect(); let scan_window = match (&node.payload, node.output_state.timing) { (Payload::NonASAP(NonASAPOp::Scan { .. }), ExecutionTiming::QueryTime) => { - match dag.scan_window(node.id, kept_chains) { + match dag.scan_window(node.id, materialized_chains) { // Priced as before #955 decides `@` anchors and // unwindowed readers: the widest window read. ScanWindow::Unbounded => trailing_window( - widest_window_read_ms(dag, nodes, node.id, kept_chains) + widest_window_read_ms(dag, nodes, node.id, materialized_chains) .or(root_scan_lookback_ms), ), window => window, @@ -1603,7 +1605,7 @@ pub type NodeMap<'a> = /// tumbling window per evaluation). Each evaluation builds the newest tumbling window, and the /// older ones, which complete the readers' look-back, are kept from /// earlier evaluations. -pub fn kept_tumbling_window_chains(dag: &PhysicalASAPDAG) -> HashSet { +pub fn materialized_tumbling_window_chains(dag: &PhysicalASAPDAG) -> HashSet { dag.nodes .iter() .filter(|node| { @@ -1623,14 +1625,14 @@ pub fn kept_tumbling_window_chains(dag: &PhysicalASAPDAG) -> HashSet, scan: PhysicalASAPNodeId, - kept_chains: &HashSet, + materialized_chains: &HashSet, ) -> Option { let mut widest = None; let mut stack = vec![scan]; @@ -1645,7 +1647,7 @@ fn widest_window_read_ms( Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { tumbling_window_width_ms, .. - }) if kept_chains.contains(&edge.consumer) => *tumbling_window_width_ms, + }) if materialized_chains.contains(&edge.consumer) => *tumbling_window_width_ms, Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { tumbling_window_width_ms, tumbling_window_count, diff --git a/crates/cost/tests/held_memory.rs b/crates/cost/tests/held_memory.rs index ac1954509..079b7ea16 100644 --- a/crates/cost/tests/held_memory.rs +++ b/crates/cost/tests/held_memory.rs @@ -1,11 +1,11 @@ -//! Query-time working memory in [`plan_cost`]: how long a not-kept +//! Query-time working memory in [`plan_cost`]: how long a not-materialized //! node's working memory is held depends on whether a materialized node //! reads it. use asap_cost::execution_demand::evaluation_rate; use asap_cost::ResourceUnitCost; use asap_cost::{ - kept_tumbling_window_chains, node_map, plan_cost, CostInputs, CostModel, PlanCost, + materialized_tumbling_window_chains, node_map, plan_cost, CostInputs, CostModel, PlanCost, }; use asap_logical_asap_optimization::test_support::lower_promql; use asap_physical_asap_optimization::optimize_physical_asap; @@ -56,7 +56,7 @@ fn cost(dag: &PhysicalASAPDAG, cost_per_memory_byte_second: f64) -> PlanCost { plan_cost( dag, &nodes, - &kept_tumbling_window_chains(dag), + &materialized_tumbling_window_chains(dag), &recurrence(), &[], &data(), @@ -100,7 +100,7 @@ fn close(a: f64, b: f64) -> bool { /// `bytes · rate · latency_0`, not the rate-weighted mean of the two /// latencies. #[test] -fn working_memory_read_by_a_kept_node_is_held_for_the_longest_reader() { +fn working_memory_read_by_a_materialized_node_is_held_for_the_longest_reader() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let plans = optimize_physical_asap( @@ -129,10 +129,10 @@ fn working_memory_read_by_a_kept_node_is_held_for_the_longest_reader() { let [outer_ms, inner_ms] = latency_ms(recomputed); assert!(outer_ms > inner_ms, "{outer_ms} vs {inner_ms}"); let below = |dag: &PhysicalASAPDAG| { - let kept_node = dag.roots[1]; + let materialized_node = dag.roots[1]; held_memory_costs(dag) .into_iter() - .filter(move |(id, _, _)| *id != kept_node && *id != dag.roots[0]) + .filter(move |(id, _, _)| *id != materialized_node && *id != dag.roots[0]) .collect::>() }; let checked = below(recomputed); @@ -144,7 +144,7 @@ fn working_memory_read_by_a_kept_node_is_held_for_the_longest_reader() { // Below a `OneEvaluation` node: the longest reader's latency at the // materialized node's rate (its readers' schedules together). - let kept_rate = evaluation_rate( + let materialized_rate = evaluation_rate( recurrence().iter().map(|r| (r, None)), CostInputs::default().non_repeating_query_horizon_seconds, ) @@ -155,7 +155,7 @@ fn working_memory_read_by_a_kept_node_is_held_for_the_longest_reader() { assert!(!checked.is_empty(), "the nodes below it hold memory"); for (id, bytes, term) in checked { assert_eq!(lifetime_of(shared, id), Lifetime::None); - let expected = bytes * kept_rate * outer_ms / 1_000.0; + let expected = bytes * materialized_rate * outer_ms / 1_000.0; assert!(close(term, expected), "node {id}: {term} vs {expected}"); } } diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index 408fc141e..7b69b7381 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -1,4 +1,4 @@ -//! How often a not-kept node is computed for the views refreshed +//! How often a not-materialized node is computed for the views refreshed //! at ingestion above it ([`computations`]): once per refresh window, since //! a runtime refreshes the views of one refresh window in one ingestion run //! (issue #1151). @@ -73,7 +73,7 @@ fn chain( } /// One query per summary of `summaries`, merging it, with each summary -/// kept with `kept` (`None`: not kept): the DAG Stage 3 costs, chains +/// materialized with `materialized` (`None`: not materialized): the DAG Stage 3 costs, chains /// unexpanded. fn dag_of(summaries: &[Rc], kept: Option) -> PhysicalASAPDAG { let mut assignment = PhysicalPropertiesAssignment::default(); @@ -143,7 +143,7 @@ fn a_scan_under_two_chains_of_one_tumbling_window_width_is_computed_once() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (1, 1.0)); } @@ -159,13 +159,13 @@ fn a_scan_under_chains_of_two_tumbling_window_widths_is_computed_for_each() { chain(&scan, SketchAlgorithm::Kll, 10_000, 6), chain(&scan, SketchAlgorithm::DDSketch, 60_000, 5), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } /// Query consumers are unchanged: with both chains built at query time -/// (not kept), each query computes the `Scan` at its own rate. +/// (not materialized), each query computes the `Scan` at its own rate. #[test] fn query_consumers_still_count_once_each() { let scan = scan(); @@ -209,7 +209,7 @@ fn a_scan_under_chains_of_10_10_and_60_s_is_computed_for_each_width() { chain(&scan, SketchAlgorithm::DDSketch, 10_000, 30), chain(&scan, SketchAlgorithm::Kll, 60_000, 5), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -229,7 +229,7 @@ fn chains_of_one_width_and_two_phases_are_computed_apart() { 30, ), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (2, 2.0)); } @@ -244,7 +244,7 @@ fn nodes_below_a_shared_intermediate_node_are_computed_once_per_run() { chain(&shift, SketchAlgorithm::Kll, 10_000, 6), chain(&shift, SketchAlgorithm::DDSketch, 10_000, 30), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!(scan_computations(&dag), (1, 1.0)); assert_eq!( @@ -278,7 +278,7 @@ fn consumers_of_unbounded_windows_count_alone() { build(SketchAlgorithm::Kll), build(SketchAlgorithm::DDSketch), ], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); assert_eq!( computations_of(&dag, |op| matches!(op, NonASAPOp::Values { .. })), @@ -293,12 +293,12 @@ fn an_invalid_node_is_reported_not_skipped() { let scan = scan(); let mut dag = dag_of( &[chain(&scan, SketchAlgorithm::Kll, 10_000, 6)], - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION), ); let chain = dag .nodes .iter_mut() - .find(|node| node.lifetime.is_kept()) + .find(|node| node.lifetime.is_materialized()) .unwrap(); chain.lifetime = asap_types::physical::Lifetime::OneEvaluation(asap_types::physical::Medium::Memory); diff --git a/crates/devtools/src/candidate_labels.rs b/crates/devtools/src/candidate_labels.rs index 3939d26ed..e266a0301 100644 --- a/crates/devtools/src/candidate_labels.rs +++ b/crates/devtools/src/candidate_labels.rs @@ -496,7 +496,7 @@ mod tests { .iter() .filter(|node| { node.output_state.timing == ExecutionTiming::IngestionTime - && node.lifetime.is_kept() + && node.lifetime.is_materialized() && matches!( node.payload, Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) diff --git a/crates/devtools/tests/asap_planner.rs b/crates/devtools/tests/asap_planner.rs index 8ea70745e..45a6332b5 100644 --- a/crates/devtools/tests/asap_planner.rs +++ b/crates/devtools/tests/asap_planner.rs @@ -1605,7 +1605,7 @@ fn scans_projecting_different_labels_are_shared() { false, &mut |_, readers, options| { let kept = (readers.len() > 1) - .then_some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); + .then_some(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION); options.iter().position(|option| *option == kept) }, ) diff --git a/crates/executor/src/physical_planner/mod.rs b/crates/executor/src/physical_planner/mod.rs index 744a42127..1c9d24415 100644 --- a/crates/executor/src/physical_planner/mod.rs +++ b/crates/executor/src/physical_planner/mod.rs @@ -1721,7 +1721,7 @@ pub mod test_support { use std::collections::HashMap; /// The materialized views at `nodes`, in that order: each node that is - /// not a view is marked kept at ingestion time, and it and every node below it + /// not a view is marked materialized at ingestion time, and it and every node below it /// run at ingestion time (their outputs and outgoing edges); then every /// view's `retention_ms` is set ([`PhysicalASAPDAG::set_retention`]) /// with no tumbling window or range-evaluation span. For tests that bind states at diff --git a/crates/executor/tests/precompute_candidates.rs b/crates/executor/tests/precompute_candidates.rs index 5187450f6..b540f8110 100644 --- a/crates/executor/tests/precompute_candidates.rs +++ b/crates/executor/tests/precompute_candidates.rs @@ -113,7 +113,7 @@ fn answer( /// Rate state. Moving Sum before Rate would answer differently across /// counter resets. #[test] -fn grouped_rate_can_be_kept_before_or_after_grouped_sum() { +fn grouped_rate_can_be_materialized_before_or_after_grouped_sum() { let dag = grouped_rate(); let state = dag .nodes diff --git a/crates/executor/tests/precompute_population.rs b/crates/executor/tests/precompute_population.rs index b5599d7cb..c62673cb0 100644 --- a/crates/executor/tests/precompute_population.rs +++ b/crates/executor/tests/precompute_population.rs @@ -30,7 +30,7 @@ fn logical_schema(family: FieldDataType) -> Schema { time_index: None, } } -/// The stored state at node 0 (kept at ingestion time): a global `family` +/// The stored state at node 0 (materialized at ingestion time): a global `family` /// `SummaryAgg` over a minute of raw `m` samples (`Scan` node `scan`, /// `TimeRange` node `scan + 1`). fn view_over_samples( diff --git a/crates/executor/tests/weighted_topk_binding.rs b/crates/executor/tests/weighted_topk_binding.rs index d02dd2197..5f3ff145f 100644 --- a/crates/executor/tests/weighted_topk_binding.rs +++ b/crates/executor/tests/weighted_topk_binding.rs @@ -126,7 +126,7 @@ fn assert_weighted_binding(algorithm: SketchAlgorithm) { }) .collect(); let batch = Batch::try_new(samples.clone(), rows).unwrap(); - // The summaries kept at ingestion time run as data arrives; not kept + // The summaries materialized at ingestion time run as data arrives; not materialized // (the default) runs everything when the query does. for (placed, scope) in [ ( @@ -267,7 +267,7 @@ fn rate_updates_cannot_enter_integer_heap_factory() { .is_err()); } -/// `candidate` with every `SummaryAgg` kept at ingestion time, the materialization +/// `candidate` with every `SummaryAgg` materialized at ingestion time, the materialization /// a continuously served query would get: each summary and every input it /// consumes run at ingestion time, the rest at query time. The candidate pins /// its finalize boundary to query time, which would put the summaries above @@ -295,7 +295,7 @@ fn continuously_maintained_dag(candidate: &Rc) if matches!(node.operator, IrOperator::ASAP(ASAPOp::SummaryAgg { .. })) { assignment.set( &node, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } } diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs index 0230c2f61..a179eb582 100644 --- a/crates/integration-tests/src/lib.rs +++ b/crates/integration-tests/src/lib.rs @@ -103,20 +103,20 @@ pub mod physical_export { }; use std::rc::Rc; - /// Time `root` under the default assignment (no sub-DAG kept, so every + /// Time `root` under the default assignment (no sub-DAG materialized, so every /// summary computed at query time). Returns the timed copy; read `node.timing` on it. pub fn timed(root: &Rc) -> Rc { timed_with(root, &PhysicalPropertiesAssignment::default()) } - /// Time `root` with every sub-DAG kept at ingestion time where the DAG + /// Time `root` with every sub-DAG materialized at ingestion time where the DAG /// allows it. pub fn at_ingestion(root: &Rc) -> Rc { timed_with( root, - &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( - root, - )), + &PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(root), + ), ) } @@ -133,7 +133,7 @@ pub mod physical_export { compile_physical_asap_dag(&timed(root)).expect("physical ASAP DAG export failed") } - /// Time `root` with every sub-DAG kept at ingestion time where the DAG allows + /// Time `root` with every sub-DAG materialized at ingestion time where the DAG allows /// it, then export the physical DAG. pub fn at_ingestion_physical_asap_dag(root: &Rc) -> PhysicalASAPDAG { compile_physical_asap_dag(&at_ingestion(root)).expect("physical ASAP DAG export failed") diff --git a/crates/integration-tests/tests/materialized_views.rs b/crates/integration-tests/tests/materialized_views.rs index 9ca195497..ffd7652e2 100644 --- a/crates/integration-tests/tests/materialized_views.rs +++ b/crates/integration-tests/tests/materialized_views.rs @@ -48,7 +48,7 @@ fn repeating_with(queries: &[&str], extra: &str) -> PlanningWorkload { /// evaluations reading its newest tumbling window, as `asap-plan-selection` prices /// it, the longest per source. fn stage3_raw_lookback_ms(dag: &PhysicalASAPDAG) -> Vec<(Source, Option)> { - let kept_chains = asap_cost::kept_tumbling_window_chains(dag); + let materialized_chains = asap_cost::materialized_tumbling_window_chains(dag); let mut lookback: Vec<(Source, Option)> = Vec::new(); for node in &dag.nodes { let Operator::NonASAP(NonASAPOp::Scan { source, .. }) = &node.payload else { @@ -57,7 +57,7 @@ fn stage3_raw_lookback_ms(dag: &PhysicalASAPDAG) -> Vec<(Source, Option)> { if node.output_state.timing != ExecutionTiming::QueryTime { continue; } - let scan = dag.scan_window(node.id, &kept_chains).lookback_ms(); + let scan = dag.scan_window(node.id, &materialized_chains).lookback_ms(); match lookback.iter_mut().find(|(kept, _)| kept == source) { Some((_, kept)) => *kept = kept.zip(scan).map(|(a, b)| a.max(b)), None => lookback.push((source.clone(), scan)), diff --git a/crates/integration-tests/tests/physical_common/mod.rs b/crates/integration-tests/tests/physical_common/mod.rs index 4b1970380..00fa6b554 100644 --- a/crates/integration-tests/tests/physical_common/mod.rs +++ b/crates/integration-tests/tests/physical_common/mod.rs @@ -43,7 +43,7 @@ pub fn compile_physical_asap_dag( ) } -/// As [`compile_physical_asap_dag`], with every sub-DAG kept at ingestion time +/// As [`compile_physical_asap_dag`], with every sub-DAG materialized at ingestion time /// where the DAG allows it. #[allow(dead_code)] // Not every test binary sharing this module stores states at ingestion. pub fn compile_at_ingestion_physical_asap_dag( @@ -51,7 +51,7 @@ pub fn compile_at_ingestion_physical_asap_dag( ) -> Result> { compile_with( root, - &asap_types::ir::PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed( + &asap_types::ir::PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( std::slice::from_ref(root), ), ) diff --git a/crates/integration-tests/tests/physical_properties_e2e.rs b/crates/integration-tests/tests/physical_properties_e2e.rs index b0d323ed3..07e2a27cd 100644 --- a/crates/integration-tests/tests/physical_properties_e2e.rs +++ b/crates/integration-tests/tests/physical_properties_e2e.rs @@ -1,6 +1,6 @@ //! Materialization decides placement, not answers: the same selected DAG -//! timed with its states not kept (everything at query time) and -//! kept at ingestion time (materialized views refreshed at ingestion time) +//! timed with its states not materialized (everything at query time) and +//! materialized at ingestion time (materialized views refreshed at ingestion time) //! executes to the same result. use std::collections::{BTreeMap, HashMap}; @@ -78,7 +78,9 @@ fn sketch_candidate(query: &str) -> Rc { fn placements(root: &Rc) -> [PhysicalPropertiesAssignment; 2] { [ PhysicalPropertiesAssignment::default(), - PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)), + PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(root), + ), ] } @@ -201,7 +203,7 @@ fn values_1_to_100(schema: &SchemaRef, _metric: &str) -> Batch { Batch::try_new(schema.clone(), rows).unwrap() } -/// Keeping it at ingestion time puts the quantile's state in a materialized view; +/// Materializing it at ingestion time puts the quantile's state in a materialized view; /// Not keeping it has no view and reads the raw source at /// query time; both answer alike. #[test] @@ -223,8 +225,8 @@ fn physical_properties_decide_precompute_contents() { assert_eq!(answers[0], answers[1]); } -/// Mixed placement in one DAG: one summary kept at ingestion time (a materialized view) -/// and the other not kept (built from the raw source at query +/// Mixed placement in one DAG: one summary materialized at ingestion time (a materialized view) +/// and the other not materialized (built from the raw source at query /// time) answer like the all-query-time placement. #[test] fn mixed_placement_answers_like_query_time() { @@ -257,7 +259,7 @@ fn mixed_placement_answers_like_query_time() { let mut mixed = PhysicalPropertiesAssignment::default(); mixed.set( &sketches(&root)[0], - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let mut answers = Vec::new(); for assignment in [PhysicalPropertiesAssignment::default(), mixed] { @@ -346,13 +348,13 @@ fn arithmetic_over_one_selector_executes() { ("m", "a", 290, 2.0), ("m", "b", 250, 5.0), ]; - let [not_kept, at_ingestion] = placements(&root).map(|a| timed_dag(&root, &a)); - assert!(!ingestion_binary(¬_kept)); + let [not_materialized, at_ingestion] = placements(&root).map(|a| timed_dag(&root, &a)); + assert!(!ingestion_binary(¬_materialized)); assert!( ingestion_binary(&at_ingestion), "one selector shares its key set" ); - for dag in [not_kept, at_ingestion] { + for dag in [not_materialized, at_ingestion] { let (values, _) = execute(&dag, &job_samples(&samples), INGESTION_WINDOW, 300_000); // job a: 3 + 3 = 6; job b: 5 + 5 = 10 (mispairing a with b gives 8 and 8). // KLL at epsilon 0.01 returns an input value within 0.01 of rank 0.9; diff --git a/crates/integration-tests/tests/planner_layering_common/mod.rs b/crates/integration-tests/tests/planner_layering_common/mod.rs index 8330db726..83ee2604b 100644 --- a/crates/integration-tests/tests/planner_layering_common/mod.rs +++ b/crates/integration-tests/tests/planner_layering_common/mod.rs @@ -660,25 +660,33 @@ pub fn assert_valid_and_uniquely_named(run: &Run) { /// optimization gives each logical candidate `L` exactly one physical /// candidate with nothing materialized, `P`, and one `P-m` for each /// other physical properties assignment. -pub fn assert_one_not_kept_physical_candidate_per_logical(run: &Run) { +pub fn assert_one_not_materialized_physical_candidate_per_logical(run: &Run) { assert!(run.pruned.is_empty(), "pruned: {:?}", run.pruned); - let not_kept: Vec<_> = run + let not_materialized: Vec<_> = run .physical .iter() .filter(|p| !p.id.contains("-m")) .collect(); - let sources: BTreeSet<_> = not_kept.iter().map(|p| p.from_logical.as_str()).collect(); + let sources: BTreeSet<_> = not_materialized + .iter() + .map(|p| p.from_logical.as_str()) + .collect(); let logical: BTreeSet<_> = run.logical.iter().map(|c| c.id.as_str()).collect(); assert_eq!(sources, logical); - assert_eq!(not_kept.len(), run.logical.len()); + assert_eq!(not_materialized.len(), run.logical.len()); for p in &run.physical { let base = p.id.split("-m").next().unwrap(); assert_eq!(&base[1..], &p.from_logical[1..], "{}", p.id); - let not_kept = !p.id.contains("-m"); - assert_eq!(not_kept, !p.candidate.keeps_any(), "{}", p.id); - if not_kept { + let not_materialized = !p.id.contains("-m"); + assert_eq!( + not_materialized, + !p.candidate.materializes_any(), + "{}", + p.id + ); + if not_materialized { for n in &p.dag().nodes { - assert_eq!(keeping(p, n.id), Keeping::NotKept); + assert_eq!(materializing(p, n.id), Materializing::NotMaterialized); } } } @@ -688,8 +696,10 @@ pub fn assert_one_not_kept_physical_candidate_per_logical(run: &Run) { /// The physical candidates with nothing materialized, one per logical /// candidate. -pub fn not_kept(run: &Run) -> impl Iterator { - run.physical.iter().filter(|p| !p.candidate.keeps_any()) +pub fn not_materialized(run: &Run) -> impl Iterator { + run.physical + .iter() + .filter(|p| !p.candidate.materializes_any()) } /// One selected id; every other candidate rejected once, with a reason. @@ -764,16 +774,16 @@ pub fn assert_each_node_charged_per_consuming_query(run: &Run) { /// How many times each node is computed per evaluation of its consumers (#509; the /// rule of plan selection's private `computations`): 1 for a materialized -/// node; for a not-kept one, the number of consumers that reach +/// node; for a not-materialized one, the number of consumers that reach /// it. A consumer is a query (operator or scalar root) or a materialized /// node, whose walk starts at its inputs; a walk stops at materialized -/// nodes and counts each node once. The consumers kept at ingestion time of one +/// nodes and counts each node once. The consumers materialized at ingestion time of one /// refresh window share one ingestion run and count once (#1151). pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { - let kept_nodes: BTreeSet<_> = dag + let materialized_nodes: BTreeSet<_> = dag .nodes .iter() - .filter(|n| n.lifetime.is_kept()) + .filter(|n| n.lifetime.is_materialized()) .map(|n| n.id) .collect(); // Each walk's start and, for a consumer refreshed at ingestion, its @@ -787,7 +797,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { .iter() .map(|(_, expr)| (expr.operator_refs().into_iter().copied().collect(), None)), ) - .chain(kept_nodes.iter().map(|&id| { + .chain(materialized_nodes.iter().map(|&id| { let at_ingestion = dag .nodes .iter() @@ -802,7 +812,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { let mut times: BTreeMap<_, _> = dag .nodes .iter() - .map(|n| (n.id, u64::from(kept_nodes.contains(&n.id)))) + .map(|n| (n.id, u64::from(materialized_nodes.contains(&n.id)))) .collect(); // The (node, refresh window) pairs whose ingestion run is counted. let mut runs = HashSet::new(); @@ -810,7 +820,7 @@ pub fn computations(dag: &PhysicalASAPDAG) -> BTreeMap { let mut seen = HashSet::new(); let mut stack = start; while let Some(id) = stack.pop() { - if kept_nodes.contains(&id) || !seen.insert(id) { + if materialized_nodes.contains(&id) || !seen.insert(id) { continue; } if window.is_none_or(|window| runs.insert((id, window))) { @@ -831,30 +841,30 @@ pub fn evaluation_interval_ms(workload: &PlanningWorkload, query: usize) -> Opti } } -// ── Kept outputs ───────────────────────────────────────────────────────── +// ── Materialized outputs ───────────────────────────────────────────────────────── -/// Whether a node's output is kept and at which timing, without how long +/// Whether a node's output is materialized and at which timing, without how long /// (`OneEvaluation` or `AcrossEvaluations`) or its storage medium. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Keeping { +pub enum Materializing { /// Runs as data arrives; output kept until a query reads it. - KeptAtIngestion, + MaterializedAtIngestion, /// Runs when a query first needs it; output reused by the other /// queries of the evaluation, or, as query-time `AcrossEvaluations`, /// kept for later evaluations. - KeptAtQueryTime, + MaterializedAtQueryTime, /// Output discarded after its reader (lifetime `None`). - NotKept, + NotMaterialized, } /// Whether physical ASAP-aware optimization keeps `node`'s output, and at /// which timing (#667). -pub fn keeping(p: &Physical, node: NodeId) -> Keeping { +pub fn materializing(p: &Physical, node: NodeId) -> Materializing { let n = p.dag().nodes.iter().find(|n| n.id == node).expect("node"); match (n.output_state.timing, n.lifetime) { - (_, Lifetime::None) => Keeping::NotKept, - (ExecutionTiming::IngestionTime, _) => Keeping::KeptAtIngestion, - (ExecutionTiming::QueryTime, _) => Keeping::KeptAtQueryTime, + (_, Lifetime::None) => Materializing::NotMaterialized, + (ExecutionTiming::IngestionTime, _) => Materializing::MaterializedAtIngestion, + (ExecutionTiming::QueryTime, _) => Materializing::MaterializedAtQueryTime, } } diff --git a/crates/integration-tests/tests/planner_layering_example1.rs b/crates/integration-tests/tests/planner_layering_example1.rs index 6838e4bca..66d4f0124 100644 --- a/crates/integration-tests/tests/planner_layering_example1.rs +++ b/crates/integration-tests/tests/planner_layering_example1.rs @@ -442,8 +442,8 @@ fn stage1_logical_asap_optimization_candidates_are_valid_and_uniquely_named() { #[test] fn stage2_physical_asap_optimization_keeps_every_logical_candidate() { let run = pipeline(); - assert_one_not_kept_physical_candidate_per_logical(&run); - let unshared = not_kept(&run) + assert_one_not_materialized_physical_candidate_per_logical(&run); + let unshared = not_materialized(&run) .filter(|p| whole_windows(p.dag()) && !classify(p.dag(), &p.query_roots).1) .count(); assert_eq!(unshared, 3); @@ -460,7 +460,7 @@ fn stage2_physical_asap_optimization_preserves_logical_choices() { let (option, shared) = classify(p.dag(), &p.query_roots); let (logical_option, logical_shared) = classify(&source.dag, &source.query_roots); assert_eq!(option, logical_option, "{} vs {}", p.id, source.id); - if !p.candidate.keeps_any() { + if !p.candidate.materializes_any() { assert_eq!(shared, logical_shared, "{} vs {}", p.id, source.id); } } @@ -568,15 +568,15 @@ fn stage2_physical_asap_optimization_summary_topk_is_build_then_estimate() { /// with every chain at query time, since a chain maintained at ingestion /// time leaves one query reading the input at query time. #[test] -fn stage2_physical_asap_optimization_keeps_only_tumbling_windows_at_ingestion() { +fn stage2_physical_asap_optimization_materializes_only_tumbling_windows_at_ingestion() { let run = pipeline(); let mut counter_maintained = 0; let mut shared_once = 0; for p in &run.physical { for n in &p.dag().nodes { - match keeping(p, n.id) { - Keeping::NotKept => {} - Keeping::KeptAtIngestion => { + match materializing(p, n.id) { + Materializing::NotMaterialized => {} + Materializing::MaterializedAtIngestion => { let Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { family, .. }) = p.dag().payload(n.id) else { @@ -593,7 +593,7 @@ fn stage2_physical_asap_optimization_keeps_only_tumbling_windows_at_ingestion() counter_maintained += 1; } } - Keeping::KeptAtQueryTime => { + Materializing::MaterializedAtQueryTime => { let (q1, q2) = roots(&p.query_roots); assert!( closure(p.dag(), q1).contains(&n.id) @@ -723,7 +723,7 @@ fn stage3_plan_selection_count_min_needs_the_counter_declaration() { ); } -/// A shared not-kept input is charged once per consumer, and both +/// A shared not-materialized input is charged once per consumer, and both /// queries read the same 1 m window, so the shared-input candidates cost /// what the independent one does; their totals differ from it only by /// floating-point rounding (the same charges summed in another grouping). @@ -742,7 +742,7 @@ fn stage3_plan_selection_shared_input_ties_up_to_rounding_unless_built_once() { p.dag() .nodes .iter() - .any(|n| keeping(p, n.id) == Keeping::KeptAtQueryTime) + .any(|n| materializing(p, n.id) == Materializing::MaterializedAtQueryTime) }; let shared: Vec<_> = run .physical @@ -770,7 +770,7 @@ fn stage3_plan_selection_shared_input_ties_up_to_rounding_unless_built_once() { .dag() .nodes .iter() - .find(|n| keeping(selected, n.id) == Keeping::KeptAtQueryTime) + .find(|n| materializing(selected, n.id) == Materializing::MaterializedAtQueryTime) .unwrap(); assert_eq!( relational(&time_range.payload).as_deref(), @@ -817,7 +817,7 @@ fn stage3_plan_selection_selects_cheapest_valid() { } /// Every node of a valid candidate is charged once per consumer that reads -/// it: a shared not-kept node is recomputed for each query, and a +/// it: a shared not-materialized node is recomputed for each query, and a /// materialized one is computed once. #[test] fn stage3_plan_selection_charges_each_node_per_consuming_query() { @@ -825,11 +825,11 @@ fn stage3_plan_selection_charges_each_node_per_consuming_query() { } /// A hand-built candidate with a materialized node: Q1's plan read by two -/// queries, its `time_range` kept `OneEvaluation`. Plan selection charges the +/// queries, its `time_range` materialized `OneEvaluation`. Plan selection charges the /// two accumulators (rate, sum) and their finalizations twice, once per query; the walks from /// both roots stop at the materialized `time_range`, which is computed once /// and reads the scan once. -fn kept_case() -> Run { +fn materialized_case() -> Run { let mut workload = example1(); let repeating = workload.query_workload.repeating_queries.as_mut().unwrap(); repeating.truncate(1); @@ -871,8 +871,8 @@ fn kept_case() -> Run { /// The charging helper agrees with plan selection when a node is /// materialized. #[test] -fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_kept_node() { - let run = kept_case(); +fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_materialized_node() { + let run = materialized_case(); let p = &run.physical[0]; let mut by_kind: Vec<_> = run.selection.costs[&p.id] .per_node @@ -898,8 +898,8 @@ fn stage3_plan_selection_charging_helper_follows_plan_selection_with_a_kept_node /// Charging the scan under a materialized node once per query is caught. #[test] #[should_panic(expected = "multiplier of")] -fn stage3_plan_selection_charging_helper_rejects_recounting_below_a_kept_node() { - let mut run = kept_case(); +fn stage3_plan_selection_charging_helper_rejects_recounting_below_a_materialized_node() { + let mut run = materialized_case(); let p = run.physical[0].clone(); let scan = p .dag() diff --git a/crates/integration-tests/tests/planner_layering_example2.rs b/crates/integration-tests/tests/planner_layering_example2.rs index 7f6114e35..bd86c566f 100644 --- a/crates/integration-tests/tests/planner_layering_example2.rs +++ b/crates/integration-tests/tests/planner_layering_example2.rs @@ -664,7 +664,7 @@ fn stage1_logical_asap_optimization_candidates_are_valid_and_uniquely_named() { /// No candidate is discarded before plan selection: each logical candidate keeps one physical candidate with nothing materialized, plus one per other physical properties assignment. #[test] fn stage2_physical_asap_optimization_keeps_every_logical_candidate() { - assert_one_not_kept_physical_candidate_per_logical(&pipeline()); + assert_one_not_materialized_physical_candidate_per_logical(&pipeline()); } /// Physical ASAP-aware optimization keeps the shared UnivMon as one build node read by all three queries. diff --git a/crates/integration-tests/tests/planner_layering_example4.rs b/crates/integration-tests/tests/planner_layering_example4.rs index 281e6572d..0d5586463 100644 --- a/crates/integration-tests/tests/planner_layering_example4.rs +++ b/crates/integration-tests/tests/planner_layering_example4.rs @@ -66,7 +66,7 @@ fn options_of( run: &Run, form: Option, readers_count: usize, -) -> BTreeMap { +) -> BTreeMap { let logical = run .logical .iter() @@ -88,12 +88,12 @@ fn options_of( }) .map(|(id, ..)| id) .expect("the window summary survives physical ASAP-aware optimization"); - (keeping(p, id), (p.id.clone(), id)) + (materializing(p, id), (p.id.clone(), id)) }) .collect() } -fn eh_options(run: &Run) -> BTreeMap { +fn eh_options(run: &Run) -> BTreeMap { options_of(run, None, 5) } @@ -114,7 +114,7 @@ fn cost(run: &Run, id: &str) -> f64 { run.cost(id).unwrap_or_else(|| panic!("{id} is not priced")) } -use Keeping::{KeptAtIngestion, KeptAtQueryTime, NotKept}; +use Materializing::{MaterializedAtIngestion, MaterializedAtQueryTime, NotMaterialized}; // ── Constraints over every candidate ───────────────────────────────────── @@ -157,7 +157,7 @@ fn pattern_a_windows_and_offsets() -> (Vec, Vec) { /// Every materialized output of every candidate of `workload` is kept for at /// least its longest reader's `windows[q] + offsets[q]`. -fn assert_kept_outputs_cover_their_consumers( +fn assert_materialized_outputs_cover_their_consumers( workload: &PlanningWorkload, windows: &[u64], offsets: &[u64], @@ -168,12 +168,12 @@ fn assert_kept_outputs_cover_their_consumers( // A shared scan or range built once per evaluation holds its // rows within that evaluation; plan selection reads it over the // longest window above it. - let shared_rows = keeping(p, n.id) == KeptAtQueryTime + let shared_rows = materializing(p, n.id) == MaterializedAtQueryTime && matches!( relational(&n.payload).as_deref(), Some("scan" | "time_range" | "time_shift") ); - if keeping(p, n.id) == NotKept || shared_rows { + if materializing(p, n.id) == NotMaterialized || shared_rows { continue; } let need = readers(p.dag(), &p.query_roots, n.id) @@ -191,24 +191,24 @@ fn assert_kept_outputs_cover_their_consumers( /// A materialized output is kept for as long as its consumers read: it covers every reader's lookback and offset. /// The monthly variant runs in -/// `stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers`. +/// `stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers`. #[test] -fn stage2_physical_asap_optimization_kept_output_covers_its_consumers() { +fn stage2_physical_asap_optimization_materialized_output_covers_its_consumers() { let (windows, offsets) = pattern_a_windows_and_offsets(); for workload in [once(), at_rest()] { - assert_kept_outputs_cover_their_consumers(&workload, &windows, &offsets); + assert_materialized_outputs_cover_their_consumers(&workload, &windows, &offsets); } - assert_kept_outputs_cover_their_consumers(&pattern_b(), &[PATTERN_B_WINDOW_MS], &[0]); + assert_materialized_outputs_cover_their_consumers(&pattern_b(), &[PATTERN_B_WINDOW_MS], &[0]); } /// The monthly variant of -/// `stage2_physical_asap_optimization_kept_output_covers_its_consumers`: +/// `stage2_physical_asap_optimization_materialized_output_covers_its_consumers`: /// it plans 67,228 candidates, too slow for a debug build in CI. #[test] #[ignore = "slow: run in release by hand"] -fn stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers() { +fn stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers() { let (windows, offsets) = pattern_a_windows_and_offsets(); - assert_kept_outputs_cover_their_consumers(&monthly(), &windows, &offsets); + assert_materialized_outputs_cover_their_consumers(&monthly(), &windows, &offsets); } // ── Pattern A ──────────────────────────────────────────────────────────── @@ -220,7 +220,11 @@ fn stage2_physical_asap_optimization_a_shared_eh_has_three_physical_properties_o let found: BTreeSet<_> = eh_options(&run_promql(&once())).into_keys().collect(); assert_eq!( found, - BTreeSet::from([KeptAtIngestion, KeptAtQueryTime, NotKept]) + BTreeSet::from([ + MaterializedAtIngestion, + MaterializedAtQueryTime, + NotMaterialized + ]) ); } @@ -229,16 +233,19 @@ fn stage2_physical_asap_optimization_a_shared_eh_has_three_physical_properties_o #[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option() { let found: BTreeSet<_> = eh_options(&run_promql(&at_rest())).into_keys().collect(); - assert_eq!(found, BTreeSet::from([KeptAtQueryTime, NotKept])); + assert_eq!( + found, + BTreeSet::from([MaterializedAtQueryTime, NotMaterialized]) + ); } /// A materialized shared EH is one build node read by all five queries, charged once. #[test] #[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] -fn stage2_physical_asap_optimization_a_kept_eh_is_built_once_for_all_consumers() { +fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers() { let run = run_promql(&once()); for (m, (id, build)) in eh_options(&run) { - if m == NotKept { + if m == NotMaterialized { continue; } let p = run.physical(&id); @@ -261,14 +268,17 @@ fn stage2_physical_asap_optimization_a_kept_eh_is_built_once_for_all_consumers() } /// A3 rebuilds the EH for each of the five queries (plan selection charges a -/// not-kept node once per consuming query), so it costs more than A1, +/// not-materialized node once per consuming query), so it costs more than A1, /// which builds it once. #[test] #[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() { let run = run_promql(&once()); let options = eh_options(&run); - let (a1, a3) = (&options[&KeptAtQueryTime].0, &options[&NotKept].0); + let (a1, a3) = ( + &options[&MaterializedAtQueryTime].0, + &options[&NotMaterialized].0, + ); assert!( cost(&run, a3) > cost(&run, a1), "A3 {} vs A1 {}", @@ -283,7 +293,7 @@ fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() fn stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh() { let run = run_promql(&once()); let options = eh_options(&run); - let a1 = cost(&run, &options[&KeptAtQueryTime].0); + let a1 = cost(&run, &options[&MaterializedAtQueryTime].0); for (m, (id, _)) in &options { assert!(a1 <= cost(&run, id), "A1 {a1} vs {m:?} {}", cost(&run, id)); } @@ -296,7 +306,8 @@ fn stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance() { let ratio = |workload: PlanningWorkload| { let run = run_promql(&workload); let options = eh_options(&run); - cost(&run, &options[&KeptAtIngestion].0) / cost(&run, &options[&KeptAtQueryTime].0) + cost(&run, &options[&MaterializedAtIngestion].0) + / cost(&run, &options[&MaterializedAtQueryTime].0) }; let (once, monthly) = (ratio(once()), ratio(monthly())); assert!(monthly < once, "A2/A1: monthly {monthly} vs once {once}"); @@ -324,7 +335,11 @@ fn stage2_physical_asap_optimization_b_tumbling_kll_has_three_physical_propertie let found: BTreeSet<_> = options_of(&run, tumbling(), 1).into_keys().collect(); assert_eq!( found, - BTreeSet::from([KeptAtIngestion, KeptAtQueryTime, NotKept]) + BTreeSet::from([ + MaterializedAtIngestion, + MaterializedAtQueryTime, + NotMaterialized + ]) ); } @@ -336,7 +351,7 @@ fn stage2_physical_asap_optimization_b_b1_builds_at_ingestion_and_merges_at_quer &CostInputs::default(), &DeploymentCapabilities::default(), ); - let (id, build) = options_of(&run, tumbling(), 1)[&KeptAtIngestion].clone(); + let (id, build) = options_of(&run, tumbling(), 1)[&MaterializedAtIngestion].clone(); let p = run.physical(&id); assert!(runs_at_ingestion(p, build)); let estimates = estimates_of(p.dag(), build); @@ -370,7 +385,7 @@ fn stage2_physical_asap_optimization_b_tumbling_kll_has_b1_and_b2() { let options = options_of(&run, tumbling(), 1); assert_eq!( options.keys().copied().collect::>(), - BTreeSet::from([KeptAtIngestion, NotKept]) + BTreeSet::from([MaterializedAtIngestion, NotMaterialized]) ); for (id, _) in options.values() { assert!(run.cost(id).is_some(), "{id} is priced"); @@ -391,7 +406,7 @@ fn stage2_physical_asap_optimization_b_b3_keeps_query_time_windows() { &keeping_query_time_results(), ); let options = options_of(&run, tumbling(), 1); - let (id, build) = options[&KeptAtQueryTime].clone(); + let (id, build) = options[&MaterializedAtQueryTime].clone(); let p = run.physical(&id); assert!( p.dag().nodes.iter().all(|n| !runs_at_ingestion(p, n.id)), @@ -399,7 +414,7 @@ fn stage2_physical_asap_optimization_b_b3_keeps_query_time_windows() { ); assert_eq!(retention_ms(p, build), Some(PATTERN_B_WINDOW_MS)); let disk = |id: &str| run.selection.costs[id].usage.disk_bytes; - assert_eq!(disk(&id) * 5, disk(&options[&NotKept].0)); + assert_eq!(disk(&id) * 5, disk(&options[&NotMaterialized].0)); } /// The sliding-window KLL is kept from ingestion time or from query time; not materializing it is the no-window plan. @@ -417,7 +432,10 @@ fn stage2_physical_asap_optimization_b_sliding_kll_has_two_physical_properties_o ) .into_keys() .collect(); - assert_eq!(found, BTreeSet::from([KeptAtIngestion, KeptAtQueryTime])); + assert_eq!( + found, + BTreeSet::from([MaterializedAtIngestion, MaterializedAtQueryTime]) + ); } // ── Cost models (#683, #660) ───────────────────────────────────────────── @@ -452,10 +470,10 @@ fn pattern_b_candidates(run: &Run) -> PatternBCandidates { .expect("an exact candidate") .id .clone(), - whole_window_kll: options_of(run, Some(WindowForm::None), 1)[&NotKept] + whole_window_kll: options_of(run, Some(WindowForm::None), 1)[&NotMaterialized] .0 .clone(), - b1: tumbling_windows[&KeptAtIngestion].0.clone(), + b1: tumbling_windows[&MaterializedAtIngestion].0.clone(), } } diff --git a/crates/integration-tests/tests/production_rollup_workloads.rs b/crates/integration-tests/tests/production_rollup_workloads.rs index 6209bed94..6643ddf18 100644 --- a/crates/integration-tests/tests/production_rollup_workloads.rs +++ b/crates/integration-tests/tests/production_rollup_workloads.rs @@ -211,7 +211,7 @@ fn production_promql_compares_rollup_with_exact() { ); } -// Price the same workload with independently built, not_kept KLL states. +// Price the same workload with independently built, not_materialized KLL states. fn independent_kll_cost( roots: Vec, entries: &[QueryWorkloadEntry], @@ -262,7 +262,7 @@ fn independent_kll_cost( entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(0), // option 0: not kept + &mut |_, _, _| Some(0), // option 0: not materialized ) .unwrap() .unwrap(); diff --git a/crates/integration-tests/tests/range_evaluation.rs b/crates/integration-tests/tests/range_evaluation.rs index 1d3ccc091..897d2921d 100644 --- a/crates/integration-tests/tests/range_evaluation.rs +++ b/crates/integration-tests/tests/range_evaluation.rs @@ -177,7 +177,7 @@ fn tumbling_window_chains(run: &Run) -> Vec<(String, u64, (ExecutionTiming, Life .collect() } -/// The candidate whose single tumbling-window chain runs at and is kept as +/// The candidate whose single tumbling-window chain runs at and is materialized as /// `wanted`. fn with_chain(run: &Run, wanted: (ExecutionTiming, Lifetime)) -> String { tumbling_window_chains(run) diff --git a/crates/integration-tests/tests/rollup_controlled.rs b/crates/integration-tests/tests/rollup_controlled.rs index 17c94dffb..75146cc1f 100644 --- a/crates/integration-tests/tests/rollup_controlled.rs +++ b/crates/integration-tests/tests/rollup_controlled.rs @@ -126,7 +126,7 @@ fn controlled_distinct_rollup_prices_the_original_workload() { ) }) }); - // Option 0: not kept. + // Option 0: not materialized. Some(match shared { Some(index) if builds.contains(&node) => index, _ => 0, diff --git a/crates/integration-tests/tests/runtime_handoff.rs b/crates/integration-tests/tests/runtime_handoff.rs index b8063e039..d937dcd6c 100644 --- a/crates/integration-tests/tests/runtime_handoff.rs +++ b/crates/integration-tests/tests/runtime_handoff.rs @@ -61,8 +61,11 @@ async fn plan(workload: &PlanningWorkload, capabilities: &DeploymentCapabilities .expect("Example 4b plans") } -fn kept_count(dag: &PhysicalASAPDAG) -> usize { - dag.nodes.iter().filter(|n| n.lifetime.is_kept()).count() +fn materialized_count(dag: &PhysicalASAPDAG) -> usize { + dag.nodes + .iter() + .filter(|n| n.lifetime.is_materialized()) + .count() } /// Without raw data Stage 3 selects ingestion-time tumbling windows; the facade's @@ -74,7 +77,7 @@ async fn export_carries_the_selected_lifetime() { let output = plan(&example4b(), &capabilities).await; let dag = output.physical_asap_dag().expect("exports"); assert!( - kept_count(&dag) > 0, + materialized_count(&dag) > 0, "the selected tumbling windows are stored" ); assert!(dag @@ -130,7 +133,7 @@ async fn installable_plan_has_its_tumbling_window_chains_expanded() { let dag = &installed.dag; let views = plan.materialized_views().unwrap(); assert_eq!(tumbling_window_chain_count(dag), 0); - assert_eq!(kept_count(dag), views.len()); + assert_eq!(materialized_count(dag), views.len()); let roots: Vec = dag.roots.iter().map(|&r| r as u64).collect(); let compiled = compile(dag, &views, &roots).expect("the executor compiles it"); assert_eq!(plan.query_texts.len(), 1); @@ -193,7 +196,7 @@ async fn reference_plan_runs_the_installable_plan_at_query_time() { let plan = installable(&example4b()).await; let reference = query_time_reference(&plan).expect("re-times"); reference.validate().unwrap(); - assert_eq!(kept_count(&reference.dag), 0); + assert_eq!(materialized_count(&reference.dag), 0); assert!(reference.materialized_views().unwrap().is_empty()); // The reference reads the raw data the plan's views were refreshed from. let [retention] = reference.raw_data_retention().unwrap().try_into().unwrap(); diff --git a/crates/integration-tests/tests/sharing_issue_regressions.rs b/crates/integration-tests/tests/sharing_issue_regressions.rs index 5963efbd3..09fa114ec 100644 --- a/crates/integration-tests/tests/sharing_issue_regressions.rs +++ b/crates/integration-tests/tests/sharing_issue_regressions.rs @@ -59,7 +59,7 @@ fn cost(w: &FuzzWorkload) -> f64 { /// #923: deriving the coarse sum costs only a sum over the 150 fine groups. /// Stage 2 offers that plan; Stage 3 keeps a `OneEvaluation` build whose -/// not-kept sibling would avoid a second scan (#1142). +/// not-materialized sibling would avoid a second scan (#1142). #[test] #[ignore = "Stage 3 misses the cheaper plan Stage 2 offers (#1142)"] fn exact_coarse_sum_reuses_fine_sum() { diff --git a/crates/integration-tests/tests/tumbling_window_merge.rs b/crates/integration-tests/tests/tumbling_window_merge.rs index 3be17cd43..64ffd6604 100644 --- a/crates/integration-tests/tests/tumbling_window_merge.rs +++ b/crates/integration-tests/tests/tumbling_window_merge.rs @@ -270,7 +270,7 @@ fn execute(root: &Rc, samples: &[RawDataSample]) -> Vec run(&plan, raw_store(&exported.dag, samples), query_scope()) } -/// Build the tumbling windows in ingestion runs (kept at ingestion time, each with its +/// Build the tumbling windows in ingestion runs (materialized at ingestion time, each with its /// own build timestamp), then merge them in the query run (Pattern B1). fn execute_retained( root: &Rc, @@ -281,14 +281,14 @@ fn execute_retained( for tumbling_window in tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } execute_retained_as(root, &assignment, samples) } /// The planner's tumbling-window chain maintained at ingestion time, as Stage 2's B1 -/// option assigns it (kept at ingestion time on the chain), then expanded: each +/// option assigns it (materialized at ingestion time on the chain), then expanded: each /// tumbling window carries the chain's timing and lifetime, so the tumbling windows are /// built in ingestion runs and merged in the query run. fn execute_maintained_chain( @@ -302,7 +302,7 @@ fn execute_maintained_chain( let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &chain, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(planned, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); diff --git a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs index 37b573d33..30a8c5fe3 100644 --- a/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs +++ b/crates/logical-asap-optimization/src/pass1/per_computation_candidates.rs @@ -834,7 +834,7 @@ pub fn generate_per_computation_candidates( if !seen.insert(Rc::as_ptr(&node)) { continue; } - if node.timing.is_some() || node.lifetime.is_kept() { + if node.timing.is_some() || node.lifetime.is_materialized() { return Err(PerComputationCandidateError::AssignedPhysicalAnnotation); } for child in node.children() { diff --git a/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs b/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs index dff62027e..c3fcde7d0 100644 --- a/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs +++ b/crates/logical-asap-optimization/src/pass2/memo/rules/shared_configuration_readers.rs @@ -134,7 +134,7 @@ impl SharedProducer for SummaryStates { }; // Configuration expansion precedes Stage 2. The rewrite helpers // create unassigned state; preserve any already assigned build. - if build.timing.is_some() || build.lifetime.is_kept() { + if build.timing.is_some() || build.lifetime.is_materialized() { continue; } let family = match build.asap() { diff --git a/crates/logical-asap-optimization/src/test_support.rs b/crates/logical-asap-optimization/src/test_support.rs index 306a7edc2..0476b09ea 100644 --- a/crates/logical-asap-optimization/src/test_support.rs +++ b/crates/logical-asap-optimization/src/test_support.rs @@ -219,7 +219,7 @@ pub fn time_range(range: Duration, child: Rc) -> Rc .unwrap() } -/// `root` timed under the default (every sub-DAG not kept) +/// `root` timed under the default (every sub-DAG not materialized) /// assignment — the shape export and the post-ASAP validators consume. pub fn timed(root: &Rc) -> Rc { apply_physical_properties( @@ -230,11 +230,13 @@ pub fn timed(root: &Rc) -> Rc { .expect("default physical properties apply") } -/// `root` timed with every sub-DAG kept at ingestion time where the DAG allows it. +/// `root` timed with every sub-DAG materialized at ingestion time where the DAG allows it. pub fn at_ingestion(root: &Rc) -> Rc { apply_physical_properties( root, - &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)), + &PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(root), + ), &mut NodeToTimedNodeCache::new(), ) .expect("at-ingestion physical properties apply") diff --git a/crates/physical-asap-optimization/src/catalog/configurations.rs b/crates/physical-asap-optimization/src/catalog/configurations.rs index 818498197..450dca8b2 100644 --- a/crates/physical-asap-optimization/src/catalog/configurations.rs +++ b/crates/physical-asap-optimization/src/catalog/configurations.rs @@ -9,7 +9,7 @@ use asap_types::stages::{ProducerCandidates, ProducerSetInterner}; use std::collections::HashMap; -use crate::summary_keep_eligibility; +use crate::summary_materialization_eligibility; use asap_types::ir::operator::{agg_has_exact_per_entity_kernel, Reduction}; use asap_types::ir::properties::ExecutionTiming; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode}; @@ -26,9 +26,9 @@ use asap_types::stages::{ /// [`PhysicalCandidate::may_keep_across_evaluations_per_sole_reader_query`] for `node` configured /// with `properties`: for each query in `entries`, whether -/// `summary_keep_eligibility` with that query as the only reader +/// `summary_materialization_eligibility` with that query as the only reader /// allows keeping it across evaluations. Empty unless `node` is a tumbling-window chain, -/// `properties` is query time kept `AcrossEvaluations(Memory)` and the +/// `properties` is query time materialized `AcrossEvaluations(Memory)` and the /// deployment keeps query-time results. pub fn may_keep_across_evaluations_per_sole_reader_query( node: &OperatorNode, @@ -37,7 +37,7 @@ pub fn may_keep_across_evaluations_per_sole_reader_query( data: &DataWorkload, query_time_results_retained: bool, ) -> Vec { - if properties != PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME + if properties != PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME || !matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) || !query_time_results_retained { @@ -45,8 +45,14 @@ pub fn may_keep_across_evaluations_per_sole_reader_query( } (0..entries.len()) .map(|reader| { - summary_keep_eligibility(node, &[reader], entries, data, query_time_results_retained) - .is_ok_and(|eligibility| eligibility.may_keep_across_evaluations) + summary_materialization_eligibility( + node, + &[reader], + entries, + data, + query_time_results_retained, + ) + .is_ok_and(|eligibility| eligibility.may_keep_across_evaluations) }) .collect() } @@ -116,7 +122,7 @@ pub fn enumerate_candidate_configurations( let mut source_configurations = vec![Vec::new(); source_count]; for source_id in 0..source_count { let node = &source.operator_nodes_of_candidates_for_memo_groups[source_id].physical_node; - if node.timing.is_some() || node.lifetime.is_kept() { + if node.timing.is_some() || node.lifetime.is_materialized() { return Err(ConfigurationError::AssignedExecution { candidate: source_id, }); @@ -138,44 +144,46 @@ pub fn enumerate_candidate_configurations( .enumerate() .filter_map(|(query, reached)| reached.then_some(query)) .collect::>(); - let mut alternatives = vec![PhysicalProperties::NOT_KEPT_AT_QUERY_TIME]; + let mut alternatives = vec![PhysicalProperties::NOT_MATERIALIZED_AT_QUERY_TIME]; if summary { - alternatives.push(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); + alternatives.push(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION); if queries.iter().any(|&query| { summary_properties_allowed( node, &[query], - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, entries, data, query_time_results_retained, ) }) { - alternatives - .push(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION); + alternatives.push( + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); } if matches!(node.asap(), Some(ASAPOp::SummaryTumblingWindowChain { .. })) && queries.iter().any(|&query| { summary_properties_allowed( node, &[query], - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, entries, data, query_time_results_retained, ) }) { - alternatives - .push(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME); + alternatives.push( + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + ); } } else if !forced_query { - alternatives.push(PhysicalProperties::NOT_KEPT_AT_INGESTION); + alternatives.push(PhysicalProperties::NOT_MATERIALIZED_AT_INGESTION); } // Potential reach only generates the choice. Selected-reader cardinality // and Stage 2's highest-shared rule determine actual eligibility. if !summary && queries.len() >= 2 { - alternatives.push(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); + alternatives.push(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION); } // Configurations the deployment cannot run are not generated; each is // recorded as pruned. @@ -225,7 +233,7 @@ pub fn enumerate_candidate_configurations( query_time_results_retained, ), }); - if properties == PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION { + if properties == PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION { if !summary { reader_constraints.push(ReaderConstraint::HighestSharedOneEvaluation { candidate: id, @@ -379,9 +387,13 @@ fn summary_properties_allowed( data: &DataWorkload, query_time_results_retained: bool, ) -> bool { - let Ok(eligibility) = - summary_keep_eligibility(node, readers, entries, data, query_time_results_retained) - else { + let Ok(eligibility) = summary_materialization_eligibility( + node, + readers, + entries, + data, + query_time_results_retained, + ) else { return false; }; eligibility.range_compatibility.is_ok() diff --git a/crates/physical-asap-optimization/src/catalog/inventory.rs b/crates/physical-asap-optimization/src/catalog/inventory.rs index 50a11f6a5..7990284a9 100644 --- a/crates/physical-asap-optimization/src/catalog/inventory.rs +++ b/crates/physical-asap-optimization/src/catalog/inventory.rs @@ -277,7 +277,7 @@ impl ImmediateCandidateBuilder<'_> { if let Some(&existing) = self.private_nodes.get(&Rc::as_ptr(node)) { return Ok(existing); } - if node.timing.is_some() || node.lifetime.is_kept() { + if node.timing.is_some() || node.lifetime.is_materialized() { return Err(CandidateInventoryError::Unsupported { group: self.owner.group.0 as usize, candidate: self.owner.index, diff --git a/crates/physical-asap-optimization/src/catalog/realize.rs b/crates/physical-asap-optimization/src/catalog/realize.rs index a6cc59db5..f9fa7862e 100644 --- a/crates/physical-asap-optimization/src/catalog/realize.rs +++ b/crates/physical-asap-optimization/src/catalog/realize.rs @@ -60,16 +60,17 @@ pub fn realize_selected_candidates( query_time_results_retained, &mut |logical, _, options| { let node = node_by_pointer.get(&logical).copied(); - // A node outside the selection is not kept. - let requested = node.map_or(PhysicalProperties::NOT_KEPT_AT_QUERY_TIME, |node| { - seen[node] = true; - assignments[node] - }); - // The option keeping it as requested; option `None` (not kept) + // A node outside the selection is not materialized. + let requested = + node.map_or(PhysicalProperties::NOT_MATERIALIZED_AT_QUERY_TIME, |node| { + seen[node] = true; + assignments[node] + }); + // The option keeping it as requested; option `None` (not materialized) // for a requested lifetime `None`, at either timing. let chosen = options.iter().position(|option| match option { Some(kept) => *kept == requested, - None => !requested.lifetime().is_kept(), + None => !requested.lifetime().is_materialized(), }); if chosen.is_none() { let message = format!( @@ -98,12 +99,12 @@ pub fn realize_selected_candidates( let physical_outputs = ordered_output_references(&physical.roots); let identities = paired_node_identities(&rebuilt.outputs, &physical_outputs)?; for (node, properties) in assignments.iter().enumerate() { - if properties.lifetime().is_kept() && !seen[node] { + if properties.lifetime().is_materialized() && !seen[node] { // The decoder already established node identity. Stage 2 did // not offer this selected node (e.g. a lower shared non-summary), // so the assignment is infeasible rather than an adapter failure. return Err(PhysicalCandidateError::RejectedAssignment(format!( - "selected node {node} is not an eligible kept-output node in the selected graph" + "selected node {node} is not an eligible materialized-output node in the selected graph" ))); } } @@ -231,7 +232,7 @@ mod tests { use asap_types::workload::QueryRecurrence; /// Add a node running `candidate` and, for each input, a node of its - /// first producer that is not kept (else its first producer), + /// first producer that is not materialized (else its first producer), /// recursively; returns the new node. fn select_from( physical: &PhysicalASAPMemoCandidates, @@ -248,7 +249,12 @@ mod tests { let producer = producer_candidates .iter() .copied() - .find(|s| !physical.candidates[s.0].properties.lifetime().is_kept()) + .find(|s| { + !physical.candidates[s.0] + .properties + .lifetime() + .is_materialized() + }) .unwrap_or(producer_candidates[0]); let producer = select_from(physical, producer, selected); selected.edges.push(SelectedEdge { diff --git a/crates/physical-asap-optimization/src/lib.rs b/crates/physical-asap-optimization/src/lib.rs index 497565b7b..b0ffc7c12 100644 --- a/crates/physical-asap-optimization/src/lib.rs +++ b/crates/physical-asap-optimization/src/lib.rs @@ -16,16 +16,16 @@ //! ## Materialization //! //! Each summary build (a `SummaryAgg` or a `SummaryTumblingWindowChain`) is one -//! kept-output candidate (`KeptOutputCandidate`) whose +//! materialized-output candidate (`MaterializedOutputCandidate`) whose //! output materialization may store (#509 §Materialization, Algorithm 3). //! So is the highest node of each other sub-DAG that two or more queries //! read (e.g. a `Scan` that a 1 m and a 5 m window read): one a root or a //! node only one query reads consumes. Such a node has only -//! not kept and `OneEvaluation(Memory)`, so a shared sub-DAG adds one +//! not materialized and `OneEvaluation(Memory)`, so a shared sub-DAG adds one //! option, not one per node. A summary build has up to four options: //! -//! * not kept: rebuilt at query time by every query that reads it; -//! * ingestion-time `AcrossEvaluations(Memory)`: maintained as data arrives and kept for the +//! * not materialized: rebuilt at query time by every query that reads it; +//! * ingestion-time `AcrossEvaluations(Memory)`: maintained as data arrives and materialized for the //! queries, when the build is eligible (`IngestionPruneReason`); //! * `OneEvaluation(Memory)`: built once at query time for every query of one //! evaluation that reads it and reused only within that evaluation, @@ -41,9 +41,9 @@ //! //! A build at ingestion time needs every build below it at ingestion time too //! (#509 Algorithm 3, line 13), and every shared non-summary node below it -//! not kept; other assignments are not generated. Every +//! not materialized; other assignments are not generated. Every //! other combination of options is one physical candidate, the -//! all-not-kept one first: nothing is capped. A node that one +//! all-not-materialized one first: nothing is capped. A node that one //! query reads at ingestion time and another at query time is copied, one //! copy per timing (`split_shared_by_timing`). //! @@ -212,7 +212,7 @@ pub(crate) enum IngestionPruneReason { /// These are local options, not a complete physical assignment. Ingestion still /// requires selected upstream implementations to pass timing/down-closure checks. #[derive(Debug)] -pub(crate) struct SummaryKeepEligibility { +pub(crate) struct SummaryMaterializationEligibility { pub(crate) at_ingestion: Result<(), IngestionPruneReason>, pub(crate) may_keep_across_evaluations: bool, /// A tumbling window's selected readers must also meet their range-step grids. @@ -236,13 +236,13 @@ pub(crate) enum SummaryEligibilityError { /// missing workload entries are rejected as malformed reader references. The node must carry the actual bound source/filter/window subtree, /// and `data` describes that source's arrival. This function does not implement /// operators, assign upstream timing, or prove complete execution legality. -pub(crate) fn summary_keep_eligibility( +pub(crate) fn summary_materialization_eligibility( node: &OperatorNode, selected_readers: &[usize], entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> Result { +) -> Result { if !is_summary_build(node) { return Err(SummaryEligibilityError::NotSummary); } @@ -282,7 +282,7 @@ fn summary_reader_eligibility( entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> SummaryKeepEligibility { +) -> SummaryMaterializationEligibility { let recurrences: Option> = readers .iter() .map(|&query| entries.get(query).map(|entry| &entry.recurrence)) @@ -298,7 +298,7 @@ fn summary_reader_eligibility( ) => builds_one_tumbling_window_per_evaluation(*tumbling_window_width_ms, recurrences), _ => false, }; - SummaryKeepEligibility { + SummaryMaterializationEligibility { at_ingestion: ingestion_eligibility(node, readers, entries, data), may_keep_across_evaluations, range_compatibility: check_summary_range_steps(node, readers, entries), @@ -309,7 +309,7 @@ fn summary_reader_eligibility( /// store, with its physical properties options. /// It is not a whole-workload plan like [`PhysicalWorkloadPlan`]: it is Stage /// 2's enumeration bookkeeping, and the physical candidates are the -/// combinations of the kept-output candidates' options. For example, +/// combinations of the materialized-output candidates' options. For example, /// over one metric: /// /// ```text @@ -318,12 +318,12 @@ fn summary_reader_eligibility( /// ``` /// /// If Stage 1 chose KLL tumbling windows for q1 and exact max tumbling windows for q2, Stage 2 -/// finds two kept-output candidates: +/// finds two materialized-output candidates: /// -/// | kept-output candidate | readers | options | +/// | materialized-output candidate | readers | options | /// |----------------------------------|---------|---------------------------------| -/// | Kll ×5 tumbling windows (q1) | q1 | not kept, kept at ingestion time | -/// | Max acc ×5 tumbling windows (q2) | q2 | not kept, kept at ingestion time | +/// | Kll ×5 tumbling windows (q1) | q1 | not materialized, materialized at ingestion time | +/// | Max acc ×5 tumbling windows (q2) | q2 | not materialized, materialized at ingestion time | /// /// One read by two or more queries also gets `OneEvaluation` (built once per /// evaluation and reused), and so does the highest node of a shared @@ -335,12 +335,12 @@ fn summary_reader_eligibility( /// `Filtered`, `NotRepeated`). Each physical candidate carries the /// resulting lifetimes on its `dag` nodes. #[derive(Debug, Clone)] -pub(crate) struct KeptOutputCandidate { +pub(crate) struct MaterializedOutputCandidate { /// The build in the implemented DAG. pub(crate) node: Rc, /// The queries (indices into the roots) that read it. pub(crate) readers: Vec, - /// `Ok` when kept at ingestion time is an option. + /// `Ok` when materialized at ingestion time is an option. pub(crate) at_ingestion: Result<(), IngestionPruneReason>, /// Whether query-time `AcrossEvaluations` is an option: the /// deployment keeps query-time results and it is a tumbling-window chain @@ -348,8 +348,8 @@ pub(crate) struct KeptOutputCandidate { pub(crate) may_keep_across_evaluations: bool, } -impl KeptOutputCandidate { - /// Its options, not kept first: kept at ingestion time when eligible, +impl MaterializedOutputCandidate { + /// Its options, not materialized first: materialized at ingestion time when eligible, /// `OneEvaluation` when two or more queries read it, and /// query-time `AcrossEvaluations` when it may be kept across /// evaluations. @@ -357,15 +357,17 @@ impl KeptOutputCandidate { let mut options = vec![None]; if self.at_ingestion.is_ok() { options.push(Some( - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, )); } if self.readers.len() > 1 { - options.push(Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION)); + options.push(Some( + PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION, + )); } if self.may_keep_across_evaluations { options.push(Some( - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, )); } options @@ -414,7 +416,7 @@ pub(crate) fn builds_one_tumbling_window_per_evaluation<'a>( /// Stage 2 for one CandidateLogicalASAPDAG: implement every operator /// (physical operator implementation), then one physical candidate per -/// physical properties assignment of its kept_output_candidates, the all-not-kept one +/// physical properties assignment of its materialized_output_candidates, the all-not-materialized one /// first. `entries[i]` is the workload entry of query `i` (`roots[i]`): /// its recurrence and predictability decide whether state may be kept from /// ingestion time; a missing entry is unknown. `id` is left empty for the @@ -433,30 +435,30 @@ pub fn optimize_physical_asap( data: &DataWorkload, query_time_results_retained: bool, ) -> Result, PhysicalASAPOptimizationError> { - let (implemented, _, kept_output_candidates) = + let (implemented, _, materialized_output_candidates) = implement_and_find_candidates(roots, entries, data, query_time_results_retained)?; - physical_properties_assignments(&kept_output_candidates) + physical_properties_assignments(&materialized_output_candidates) .map(|assignment| { assigned_candidate( from_logical, &implemented, - &kept_output_candidates, + &materialized_output_candidates, assignment, ) }) .collect() } -/// [`optimize_physical_asap_chosen`]'s choice per kept-output +/// [`optimize_physical_asap_chosen`]'s choice per materialized-output /// candidate, from the logical node it implements, its readers and its -/// options (`None` = not kept, always first): the index of the chosen +/// options (`None` = not materialized, always first): the index of the chosen /// option, or `None` to reject the assignment. pub(crate) type ChoosePhysicalProperties<'a> = dyn FnMut(*const OperatorNode, &[usize], &[Option]) -> Option + 'a; /// Stage 2 for one CandidateLogicalASAPDAG and one physical properties /// assignment chosen node by node: `choose(logical, readers, options)` -/// gives the option for each kept-output candidate, `logical` being +/// gives the option for each materialized-output candidate, `logical` being /// the address of the logical node of `roots` it implements (null when it /// implements none, e.g. a node the implementation adds) and `readers` the /// queries that read it. `None` when `choose` rejects, a chosen index is @@ -471,32 +473,32 @@ pub(crate) fn optimize_physical_asap_chosen( query_time_results_retained: bool, choose: &mut ChoosePhysicalProperties<'_>, ) -> Result, PhysicalASAPOptimizationError> { - let (implemented, cache, kept_output_candidates) = + let (implemented, cache, materialized_output_candidates) = implement_and_find_candidates(roots, entries, data, query_time_results_retained)?; let logical_of: HashMap<*const OperatorNode, *const OperatorNode> = cache .iter() .map(|(logical, implemented)| (Rc::as_ptr(implemented), *logical)) .collect(); - let mut assignment = Vec::with_capacity(kept_output_candidates.len()); - for kept_output_candidate in &kept_output_candidates { + let mut assignment = Vec::with_capacity(materialized_output_candidates.len()); + for materialized_output_candidate in &materialized_output_candidates { let logical = logical_of - .get(&Rc::as_ptr(&kept_output_candidate.node)) + .get(&Rc::as_ptr(&materialized_output_candidate.node)) .copied() .unwrap_or(std::ptr::null()); - let options = kept_output_candidate.options(); - let Some(&chosen) = choose(logical, &kept_output_candidate.readers, &options) + let options = materialized_output_candidate.options(); + let Some(&chosen) = choose(logical, &materialized_output_candidate.readers, &options) .and_then(|index| options.get(index)) else { return Ok(None); }; assignment.push(chosen); } - let nodes: Vec<_> = kept_output_candidates + let nodes: Vec<_> = materialized_output_candidates .iter() .map(|c| Rc::clone(&c.node)) .collect(); if !down_closed( - &kept_output_candidates, + &materialized_output_candidates, &candidates_below(&nodes), &assignment, ) { @@ -505,24 +507,26 @@ pub(crate) fn optimize_physical_asap_chosen( assigned_candidate( from_logical, &implemented, - &kept_output_candidates, + &materialized_output_candidates, assignment, ) .map(Some) } /// The physical candidate of the implemented roots `implemented` with -/// `assignment[c]` chosen for `kept_output_candidates[c]`. +/// `assignment[c]` chosen for `materialized_output_candidates[c]`. fn assigned_candidate( from_logical: &str, implemented: &[QueryRoot], - kept_output_candidates: &[KeptOutputCandidate], + materialized_output_candidates: &[MaterializedOutputCandidate], assignment: Vec>, ) -> Result { let mut options = PhysicalPropertiesAssignment::default(); - for (kept_output_candidate, kept) in kept_output_candidates.iter().zip(&assignment) { + for (materialized_output_candidate, kept) in + materialized_output_candidates.iter().zip(&assignment) + { if let Some(kept) = *kept { - options.set(&kept_output_candidate.node, kept); + options.set(&materialized_output_candidate.node, kept); } } let operators: Vec> = implemented @@ -552,7 +556,7 @@ fn assigned_candidate( } /// `roots` implemented, the implementation of each logical node, and the -/// kept-output candidates of the implemented roots. +/// materialized-output candidates of the implemented roots. fn implement_and_find_candidates( roots: &[QueryRoot], entries: &[QueryWorkloadEntry], @@ -562,16 +566,20 @@ fn implement_and_find_candidates( ( Vec, NodeToImplementedNodeCache, - Vec, + Vec, ), PhysicalASAPOptimizationError, > { let mut cache = HashMap::new(); let implemented = map_roots(roots, &mut |node| implement(node, &mut cache))?; - let kept_output_candidates = - find_kept_output_candidates(&implemented, entries, data, query_time_results_retained); - check_tumbling_windows_on_range_steps(&kept_output_candidates, entries)?; - Ok((implemented, cache, kept_output_candidates)) + let materialized_output_candidates = find_materialized_output_candidates( + &implemented, + entries, + data, + query_time_results_retained, + ); + check_tumbling_windows_on_range_steps(&materialized_output_candidates, entries)?; + Ok((implemented, cache, materialized_output_candidates)) } /// `Err` for the first tumbling-window chain whose tumbling-window width does not @@ -579,10 +587,10 @@ fn implement_and_find_candidates( /// ([`PhysicalASAPOptimizationError::TumblingWindowWidthOffRangeStep`]): that step /// would end inside a tumbling window. fn check_tumbling_windows_on_range_steps( - kept_output_candidates: &[KeptOutputCandidate], + materialized_output_candidates: &[MaterializedOutputCandidate], entries: &[QueryWorkloadEntry], ) -> Result<(), PhysicalASAPOptimizationError> { - for candidate in kept_output_candidates { + for candidate in materialized_output_candidates { check_summary_range_steps(&candidate.node, &candidate.readers, entries)?; } Ok(()) @@ -628,7 +636,7 @@ fn is_summary_build(node: &OperatorNode) -> bool { ) } -/// The kept-output candidates of `roots` (implemented), with their +/// The materialized-output candidates of `roots` (implemented), with their /// readers, whether each may run at ingestion time and whether it may be /// kept from query time across evaluations: every summary build, in /// discovery order, then every highest shared non-summary node, in @@ -636,12 +644,12 @@ fn is_summary_build(node: &OperatorNode) -> bool { /// highest are those a root or an unshared node reads (e.g. a `Scan` that /// two windows read). Only a highest one is offered `OneEvaluation`, so a /// shared sub-DAG adds one candidate, not one per node. -pub(crate) fn find_kept_output_candidates( +pub(crate) fn find_materialized_output_candidates( roots: &[QueryRoot], entries: &[QueryWorkloadEntry], data: &DataWorkload, query_time_results_retained: bool, -) -> Vec { +) -> Vec { let mut reached: Vec> = Vec::new(); let mut readers: HashMap<*const OperatorNode, Vec> = HashMap::new(); let mut consumers: HashMap<*const OperatorNode, Vec<*const OperatorNode>> = HashMap::new(); @@ -688,14 +696,14 @@ pub(crate) fn find_kept_output_candidates( for &v in below[c].iter().chain([&c]) { trial.set( &nodes[v], - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } apply_physical_properties(node, &trial, &mut NodeToTimedNodeCache::new()) .map(|_| ()) .map_err(|e| IngestionPruneReason::UpstreamAtQueryTime(e.to_string())) }); - KeptOutputCandidate { + MaterializedOutputCandidate { node: Rc::clone(node), readers, at_ingestion, @@ -706,7 +714,7 @@ pub(crate) fn find_kept_output_candidates( let shared_results = shared_results .into_iter() .filter(|n| highest_shared(n) && n.timing != Some(ExecutionTiming::IngestionTime)) - .map(|node| KeptOutputCandidate { + .map(|node| MaterializedOutputCandidate { readers: readers[&Rc::as_ptr(&node)].clone(), node, at_ingestion: Err(IngestionPruneReason::NotASummaryBuild), @@ -785,7 +793,7 @@ fn ingestion_eligibility( tumbling_window_width_ms, .. }) => (family, Some(*tumbling_window_width_ms)), - _ => unreachable!("a kept-output candidate is a summary build"), + _ => unreachable!("a materialized-output candidate is a summary build"), }; if matches!( family, @@ -918,13 +926,13 @@ fn candidates_below(nodes: &[Rc]) -> Vec> { /// Whether, below every ingestion-time build of `assignment`, every build /// is at ingestion time too and every shared non-summary node is -/// not kept: ingestion work reads it as it arrives, and its +/// not materialized: ingestion work reads it as it arrives, and its /// query-time readers read a copy ([`split_shared_by_timing`]). /// Simplification: that copy is not offered `OneEvaluation` even when two /// query-time readers remain. `below` is [`candidates_below`] of -/// `kept_output_candidates`. +/// `materialized_output_candidates`. fn down_closed( - kept_output_candidates: &[KeptOutputCandidate], + materialized_output_candidates: &[MaterializedOutputCandidate], below: &[Vec], assignment: &[Option], ) -> bool { @@ -934,7 +942,7 @@ fn down_closed( assignment.iter().enumerate().all(|(c, m)| { !at_ingestion(m) || below[c].iter().all(|&v| { - if is_summary_build(&kept_output_candidates[v].node) { + if is_summary_build(&materialized_output_candidates[v].node) { at_ingestion(&assignment[v]) } else { assignment[v].is_none() @@ -943,21 +951,23 @@ fn down_closed( }) } -/// Every assignment of an option to each kept-output candidate (mixed -/// radix, the last varying fastest, all not kept first) that is +/// Every assignment of an option to each materialized-output candidate (mixed +/// radix, the last varying fastest, all not materialized first) that is /// [`down_closed`]. #[cfg(any(test, feature = "reference-pricer"))] fn physical_properties_assignments( - kept_output_candidates: &[KeptOutputCandidate], + materialized_output_candidates: &[MaterializedOutputCandidate], ) -> impl Iterator>> + '_ { - let options: Vec>> = - kept_output_candidates.iter().map(|c| c.options()).collect(); - let nodes: Vec<_> = kept_output_candidates + let options: Vec>> = materialized_output_candidates + .iter() + .map(|c| c.options()) + .collect(); + let nodes: Vec<_> = materialized_output_candidates .iter() .map(|c| Rc::clone(&c.node)) .collect(); let below = candidates_below(&nodes); - let mut digits = Some(vec![0usize; kept_output_candidates.len()]); + let mut digits = Some(vec![0usize; materialized_output_candidates.len()]); std::iter::from_fn(move || loop { let current = digits.as_mut()?; let assignment: Vec> = current @@ -978,7 +988,7 @@ fn physical_properties_assignments( if carried { digits = None; } - if down_closed(kept_output_candidates, &below, &assignment) { + if down_closed(materialized_output_candidates, &below, &assignment) { return Some(assignment); } digits.as_ref()?; @@ -1239,7 +1249,7 @@ mod tests { ); } - /// The all-not-kept candidate, with no workload declared. + /// The all-not-materialized candidate, with no workload declared. fn first_candidate(roots: &[QueryRoot]) -> PhysicalWorkloadPlan { optimize_physical_asap("L1", roots, &[], &DataWorkload::default(), false) .unwrap() @@ -1562,7 +1572,7 @@ mod tests { .nodes .iter() .map(|node| node.lifetime) - .filter(|lifetime| lifetime.is_kept()) + .filter(|lifetime| lifetime.is_materialized()) .collect() } @@ -1585,24 +1595,38 @@ mod tests { ]; let data = arriving(); let query_time_results_retained = false; - let selected = - summary_keep_eligibility(&node, &[0, 0], &entries, &data, query_time_results_retained) - .unwrap(); + let selected = summary_materialization_eligibility( + &node, + &[0, 0], + &entries, + &data, + query_time_results_retained, + ) + .unwrap(); assert_eq!(selected.at_ingestion, Ok(())); assert!(matches!( - summary_keep_eligibility(&node, &[0, entries.len()], &entries, &data, query_time_results_retained), + summary_materialization_eligibility(&node, &[0, entries.len()], &entries, &data, query_time_results_retained), Err(SummaryEligibilityError::UnknownReader { query }) if query == entries.len() )); - let combined = - summary_keep_eligibility(&node, &[0, 1], &entries, &data, query_time_results_retained) - .unwrap(); + let combined = summary_materialization_eligibility( + &node, + &[0, 1], + &entries, + &data, + query_time_results_retained, + ) + .unwrap(); assert_eq!( combined.at_ingestion, Err(IngestionPruneReason::NotPredictable) ); // The complete-DAG path uses the same selected-reader workload rules. - let candidates = - find_kept_output_candidates(&[root], &entries, &data, query_time_results_retained); + let candidates = find_materialized_output_candidates( + &[root], + &entries, + &data, + query_time_results_retained, + ); let original = candidates .iter() .find(|candidate| { @@ -1650,28 +1674,49 @@ mod tests { ]; let query_time_results_retained = true; let data = arriving(); - let one = - summary_keep_eligibility(&node, &[0], &entries, &data, query_time_results_retained) - .unwrap(); + let one = summary_materialization_eligibility( + &node, + &[0], + &entries, + &data, + query_time_results_retained, + ) + .unwrap(); assert!(one.may_keep_across_evaluations); assert!(one.range_compatibility.is_ok()); - let different_phase = - summary_keep_eligibility(&node, &[0, 1], &entries, &data, query_time_results_retained) - .unwrap(); + let different_phase = summary_materialization_eligibility( + &node, + &[0, 1], + &entries, + &data, + query_time_results_retained, + ) + .unwrap(); assert!(!different_phase.may_keep_across_evaluations); assert_eq!( different_phase.at_ingestion, Err(IngestionPruneReason::TumblingWindowsOffPhase) ); - let off_grid = - summary_keep_eligibility(&node, &[0, 2], &entries, &data, query_time_results_retained) - .unwrap(); + let off_grid = summary_materialization_eligibility( + &node, + &[0, 2], + &entries, + &data, + query_time_results_retained, + ) + .unwrap(); assert!(matches!( off_grid.range_compatibility, Err(PhysicalASAPOptimizationError::TumblingWindowWidthOffRangeStep { .. }) )); assert!(matches!( - summary_keep_eligibility(&node, &[], &entries, &data, query_time_results_retained), + summary_materialization_eligibility( + &node, + &[], + &entries, + &data, + query_time_results_retained + ), Err(SummaryEligibilityError::NoSelectedReaders) )); } @@ -1723,7 +1768,7 @@ mod tests { let [b2, b1] = &candidates[..] else { unreachable!() }; - assert!(!b2.keeps_any()); + assert!(!b2.materializes_any()); assert!(b2 .dag .nodes @@ -1768,7 +1813,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - find_kept_output_candidates(&implemented, &demands, &arriving(), false) + find_materialized_output_candidates(&implemented, &demands, &arriving(), false) .into_iter() .find(|c| { matches!( @@ -1776,7 +1821,7 @@ mod tests { Some(ASAPOp::SummaryTumblingWindowChain { .. }) ) }) - .expect("the chain is a kept-output candidate") + .expect("the chain is a materialized-output candidate") .at_ingestion }; assert_eq!(at_ingestion([at(0), at(2 * MINUTE)]), Ok(())); @@ -1819,7 +1864,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - find_kept_output_candidates(&implemented, &demands, &arriving(), false) + find_materialized_output_candidates(&implemented, &demands, &arriving(), false) .into_iter() .find(|c| { matches!( @@ -1827,7 +1872,7 @@ mod tests { Some(ASAPOp::SummaryTumblingWindowChain { .. }) ) }) - .expect("the chain is a kept-output candidate") + .expect("the chain is a materialized-output candidate") .at_ingestion }; assert_eq!(at_ingestion([every_minute(), every(2 * MINUTE)]), Ok(())); @@ -1843,7 +1888,7 @@ mod tests { /// S4: maintaining state at ingestion time needs arriving data and /// queries that repeat and are predictable; otherwise the chain only - /// runs at query time, and the kept-output candidate says why. + /// runs at query time, and the materialized-output candidate says why. #[test] fn ingestion_time_needs_arriving_data_and_repeated_predictable_queries() { use IngestionPruneReason as Why; @@ -1876,10 +1921,10 @@ mod tests { assert_eq!(candidates.len(), 1, "{why:?}"); let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let kept_output_candidates = - find_kept_output_candidates(&implemented, &[demand], &data, false); - assert_eq!(kept_output_candidates.len(), 1); - assert_eq!(kept_output_candidates[0].at_ingestion, Err(why)); + let materialized_output_candidates = + find_materialized_output_candidates(&implemented, &[demand], &data, false); + assert_eq!(materialized_output_candidates.len(), 1); + assert_eq!(materialized_output_candidates[0].at_ingestion, Err(why)); } } @@ -1893,9 +1938,17 @@ mod tests { let roots = [in_tumbling_windows(summary_root(query))]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let kept_output_candidates = - find_kept_output_candidates(&implemented, &[every_minute()], &arriving(), false); - assert_eq!(kept_output_candidates[0].at_ingestion, Ok(()), "{query}"); + let materialized_output_candidates = find_materialized_output_candidates( + &implemented, + &[every_minute()], + &arriving(), + false, + ); + assert_eq!( + materialized_output_candidates[0].at_ingestion, + Ok(()), + "{query}" + ); let candidates = optimize_physical_asap("L1", &roots, &[every_minute()], &arriving(), false) .unwrap(); @@ -1924,10 +1977,10 @@ mod tests { let roots = [root]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - let kept_output_candidates = - find_kept_output_candidates(&implemented, &[every_minute()], &data, false); + let materialized_output_candidates = + find_materialized_output_candidates(&implemented, &[every_minute()], &data, false); assert_eq!( - kept_output_candidates[0].at_ingestion, + materialized_output_candidates[0].at_ingestion, Err(Why::CounterNeedsTimeOrder) ); } @@ -1968,60 +2021,69 @@ mod tests { ..every_minute() }; let at = |interval_ms: u32| at_phase(interval_ms, 0); - let kept_output_candidates = |root: &QueryRoot, demand: QueryWorkloadEntry| { + let materialized_output_candidates = |root: &QueryRoot, demand: QueryWorkloadEntry| { let mut cache = HashMap::new(); let implemented = map_roots(std::slice::from_ref(root), &mut |n| { implement(n, &mut cache) }) .unwrap(); - find_kept_output_candidates(&implemented, &[demand], &arriving(), false) + find_materialized_output_candidates(&implemented, &[demand], &arriving(), false) .remove(0) .at_ingestion }; - assert_eq!(kept_output_candidates(&root, at(MINUTE as u32)), Ok(())); - assert_eq!(kept_output_candidates(&root, every_minute()), Ok(())); - assert_eq!(kept_output_candidates(&root, at(2 * MINUTE as u32)), Ok(())); assert_eq!( - kept_output_candidates(&root, at_phase(MINUTE as u32, 3 * MINUTE)), + materialized_output_candidates(&root, at(MINUTE as u32)), + Ok(()) + ); + assert_eq!( + materialized_output_candidates(&root, every_minute()), + Ok(()) + ); + assert_eq!( + materialized_output_candidates(&root, at(2 * MINUTE as u32)), + Ok(()) + ); + assert_eq!( + materialized_output_candidates(&root, at_phase(MINUTE as u32, 3 * MINUTE)), Ok(()) ); assert_eq!( - kept_output_candidates(&root, at_phase(MINUTE as u32, 30_000)), + materialized_output_candidates(&root, at_phase(MINUTE as u32, 30_000)), Err(Why::WindowOffEpochGrid) ); assert_eq!( - kept_output_candidates(&root, at(30_000)), + materialized_output_candidates(&root, at(30_000)), Err(Why::WindowOffEpochGrid) ); assert_eq!( - kept_output_candidates(&root, at(90_000)), + materialized_output_candidates(&root, at(90_000)), Err(Why::WindowOffEpochGrid) ); // Several readers of one build: a declared phase on the grid and an // undeclared one agree; two declared phases, or two intervals, do not. - let kept_output_candidates_of = |demands: &[QueryWorkloadEntry]| { + let materialized_output_candidates_of = |demands: &[QueryWorkloadEntry]| { let roots = vec![root.clone(); demands.len()]; let mut cache = HashMap::new(); let implemented = map_roots(&roots, &mut |n| implement(n, &mut cache)).unwrap(); - find_kept_output_candidates(&implemented, demands, &arriving(), false) + find_materialized_output_candidates(&implemented, demands, &arriving(), false) .into_iter() .find(|c| matches!(c.node.asap(), Some(ASAPOp::SummaryAgg { .. }))) - .expect("the whole-window build is a kept-output candidate") + .expect("the whole-window build is a materialized-output candidate") .at_ingestion }; assert_eq!( - kept_output_candidates_of(&[at_phase(MINUTE as u32, MINUTE), every_minute()]), + materialized_output_candidates_of(&[at_phase(MINUTE as u32, MINUTE), every_minute()]), Ok(()) ); assert_eq!( - kept_output_candidates_of(&[ + materialized_output_candidates_of(&[ at(MINUTE as u32), at_phase(MINUTE as u32, 2 * MINUTE + MINUTE / 2) ]), Err(Why::WindowNotFixed) ); assert_eq!( - kept_output_candidates_of(&[at(MINUTE as u32), at(2 * MINUTE as u32)]), + materialized_output_candidates_of(&[at(MINUTE as u32), at(2 * MINUTE as u32)]), Err(Why::WindowNotFixed) ); let candidates = optimize_physical_asap( @@ -2073,7 +2135,7 @@ mod tests { .with_guarantee(build.guarantee.clone()), ); assert_eq!( - kept_output_candidates(&QueryRoot::Operator(filtered), at(MINUTE as u32)), + materialized_output_candidates(&QueryRoot::Operator(filtered), at(MINUTE as u32)), Err(Why::Filtered) ); } @@ -2103,7 +2165,7 @@ mod tests { implement(n, &mut cache) }) .unwrap(); - find_kept_output_candidates(&implemented, &[entry], &arriving(), false) + find_materialized_output_candidates(&implemented, &[entry], &arriving(), false) .remove(0) .at_ingestion }; @@ -2252,10 +2314,10 @@ mod tests { scans.sort_by_key(|(t, _)| *t == ExecutionTiming::QueryTime); scans }; - let not_kept = Lifetime::None; + let not_materialized = Lifetime::None; assert_eq!( scans(&candidates[0]), - [(ExecutionTiming::QueryTime, not_kept)] + [(ExecutionTiming::QueryTime, not_materialized)] ); assert_eq!( scans(&candidates[1]), @@ -2267,14 +2329,14 @@ mod tests { assert_eq!( scans(&candidates[2]), [ - (ExecutionTiming::IngestionTime, not_kept), - (ExecutionTiming::QueryTime, not_kept) + (ExecutionTiming::IngestionTime, not_materialized), + (ExecutionTiming::QueryTime, not_materialized) ] ); } - /// Only the highest shared non-summary nodes are kept-output - /// candidates, each with not kept and `OneEvaluation` only: a + /// Only the highest shared non-summary nodes are materialized-output + /// candidates, each with not materialized and `OneEvaluation` only: a /// 5 m range two queries read (not the scan below it, which only that /// shared range reads for them), and the scan, which a third query /// also reads through its own 1 m range. @@ -2310,15 +2372,15 @@ mod tests { aggregate(AggIntent::Min { col: None }, five_minutes), aggregate(AggIntent::Max { col: None }, ranged(MINUTE)), ]; - let kept_output_candidates = - find_kept_output_candidates(&roots, &[], &DataWorkload::default(), false); - let found: Vec<_> = kept_output_candidates + let materialized_output_candidates = + find_materialized_output_candidates(&roots, &[], &DataWorkload::default(), false); + let found: Vec<_> = materialized_output_candidates .iter() .map(|c| (c.node.operator.kind_name(), c.readers.clone(), c.options())) .collect(); let options = vec![ None, - Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION), + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION), ]; assert_eq!( found, diff --git a/crates/physical-asap-optimization/src/split_by_timing.rs b/crates/physical-asap-optimization/src/split_by_timing.rs index a0499d496..2907e74de 100644 --- a/crates/physical-asap-optimization/src/split_by_timing.rs +++ b/crates/physical-asap-optimization/src/split_by_timing.rs @@ -130,7 +130,7 @@ mod tests { }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; - const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); + const MATERIALIZED_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); fn scan() -> Rc { OperatorNode::new_shared(Operator::NonASAP(NonASAPOp::Scan { @@ -240,7 +240,7 @@ mod tests { assert_eq!( apply_physical_properties( &root, - &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed( + &PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( std::slice::from_ref(&root) ), &mut NodeToTimedNodeCache::new() @@ -253,9 +253,9 @@ mod tests { ); let (split, assignment) = split_shared_by_timing( std::slice::from_ref(&root), - &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( - &root, - )), + &PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(&root), + ), ); assert!(apply_physical_properties( &split[0], @@ -278,7 +278,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &summary, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let (split, assignment) = split_shared_by_timing(std::slice::from_ref(&root), &assignment); let timed = @@ -289,7 +289,7 @@ mod tests { summary.operator, Operator::ASAP(ASAPOp::SummaryAgg { .. }) )); - assert_eq!(summary.lifetime, KEPT_ACROSS); + assert_eq!(summary.lifetime, MATERIALIZED_ACROSS); assert_eq!(summary.timing, Some(ExecutionTiming::IngestionTime)); } @@ -312,7 +312,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &summary, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed_unsplit = { let mut cache = NodeToTimedNodeCache::new(); @@ -333,7 +333,7 @@ mod tests { .map(|root| apply_physical_properties(root, &assignment, &mut cache).unwrap()) .collect(); let summary = child(&child(&child(&timed[0]))); - assert_eq!(summary.lifetime, KEPT_ACROSS); + assert_eq!(summary.lifetime, MATERIALIZED_ACROSS); assert_eq!(child(&summary).timing, Some(ExecutionTiming::IngestionTime)); assert_eq!( child(&child(&timed[1])).timing, @@ -362,15 +362,15 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &summary, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assignment.set( &state, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assignment.set( &read, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let (split, assignment) = split_shared_by_timing(&[pair, read], &assignment); let mut cache = NodeToTimedNodeCache::new(); @@ -384,7 +384,8 @@ mod tests { ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - assigned: PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + assigned: + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, } ) ); diff --git a/crates/plan-selection/src/groups.rs b/crates/plan-selection/src/groups.rs index 35363f45c..60122bbd5 100644 --- a/crates/plan-selection/src/groups.rs +++ b/crates/plan-selection/src/groups.rs @@ -328,15 +328,15 @@ pub(crate) enum UnusableReason { /// counts its executions: #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) enum RunKind { - /// Not kept (lifetime `None`) at query time: computed once in each execution + /// Not materialized (lifetime `None`) at query time: computed once in each execution /// context (a query evaluation, or a shared query-time candidate's /// inputs) that selects it. PerContext, - /// Not kept (lifetime `None`) at ingestion time: runs in the ingestion pipeline + /// Not materialized (lifetime `None`) at ingestion time: runs in the ingestion pipeline /// `I_r` of its readers' refresh window `r`, once per second of /// arriving data for all of them. Ingestion, - /// Kept (lifetime `OneEvaluation` or `AcrossEvaluations`, at either + /// Materialized (lifetime `OneEvaluation` or `AcrossEvaluations`, at either /// timing): selected once, its own execution context for its inputs, /// charged once. Shareable, @@ -685,7 +685,7 @@ pub(crate) enum ContextKind { /// Which ingestion pipeline `I_r` (#1095 §2.5 O3(b)): the deployment /// refreshes the ingestion-time views of one refresh window in one run, so -/// `asap_cost::execution_demand::computations` charges a not-kept +/// `asap_cost::execution_demand::computations` charges a not-materialized /// ingestion-time node once per refresh window of the views reading it. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) enum IngestionPipeline { diff --git a/crates/plan-selection/src/groups/tests.rs b/crates/plan-selection/src/groups/tests.rs index 4ac11facf..530ccda88 100644 --- a/crates/plan-selection/src/groups/tests.rs +++ b/crates/plan-selection/src/groups/tests.rs @@ -76,18 +76,18 @@ pub(super) fn catalog( ) } -/// At query time, not kept. -pub(super) fn query_time_not_kept() -> PhysicalProperties { +/// At query time, not materialized. +pub(super) fn query_time_not_materialized() -> PhysicalProperties { PhysicalProperties::new(ExecutionTiming::QueryTime, Lifetime::None).unwrap() } -/// One candidate of operator node `node` at query time, not kept, +/// One candidate of operator node `node` at query time, not materialized, /// reading `producers` per input, that may produce a query's output when /// `output`. pub(super) fn candidate(node: usize, producers: &[&[usize]], output: bool) -> PhysicalCandidate { PhysicalCandidate { operator_node: OperatorNodeOfCandidateForMemoGroupId(node), - properties: query_time_not_kept(), + properties: query_time_not_materialized(), producer_candidates_per_input: producers .iter() .map(|input| { @@ -178,7 +178,7 @@ fn dominance_needs_every_condition() { OperatorKindForReaders::Other(std::mem::discriminant(&rows_node(1).operator), "Values"); let key = DominanceKey { group: MemoGroupId(3), - properties: query_time_not_kept(), + properties: query_time_not_materialized(), shareable: false, producer_candidates_per_input: &producers, readers: vec![(PhysicalCandidateId(9), 0)], @@ -220,7 +220,7 @@ fn dominance_needs_every_condition() { ( "lifetime", DominanceKey { - properties: PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, + properties: PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION, ..key.clone() }, ), @@ -375,7 +375,7 @@ fn pruning_keeps_the_smallest_equal_class_and_incomparable_ones() { let schema = rows_node(1).schema.clone(); let key = DominanceKey { group: MemoGroupId(0), - properties: query_time_not_kept(), + properties: query_time_not_materialized(), shareable: false, producer_candidates_per_input: &producers, readers: Vec::new(), @@ -489,7 +489,7 @@ fn shared_middle() -> PhysicalASAPMemoCandidates { let candidates = vec![ candidate(0, &[], false), PhysicalCandidate { - properties: PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, + properties: PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION, ..candidate(1, &[&[0]], false) }, candidate(2, &[&[1]], true), @@ -910,11 +910,11 @@ fn kept_builds_match_fresh_builds_of(roots: Vec) -> MilpInputs { /// refresh window, (10 s, 0)); /// - 5: a KLL over `TimeRange(60 s)`, window (60 s, 0); /// - 8: a KLL over `TimeRange(10 s)` over `TimeShift(5 s)`, window -/// (10 s, 5 s), through two not-kept ingestion-time nodes; +/// (10 s, 5 s), through two not-materialized ingestion-time nodes; /// - 9: a KLL over the whole scan, an unbounded window. /// /// Candidates 0, 1, 4, 6 and 7 (the scan, ranges and shift) are -/// not kept, at ingestion time; 10–14 are the query-time readers. +/// not materialized, at ingestion time; 10–14 are the query-time readers. fn ingestion_views_of_three_windows_and_an_unbounded_one() -> PhysicalASAPMemoCandidates { use asap_types::ir::operator::{Reduction, Source, TimeShift}; use asap_types::ir::scalar::ColumnRef; @@ -1027,7 +1027,7 @@ fn ingestion_views_of_three_windows_and_an_unbounded_one() -> PhysicalASAPMemoCa // One `I_r` per refresh window: the two views over `TimeRange(10 s)` share // one; the 60 s view and the shifted 10 s view (window (10 s, 5 s), through -// a not-kept shift and range) have their own; the unbounded view +// a not-materialized shift and range) have their own; the unbounded view // gets an `Alone` one. Each `I_r` holds the scan and the stateless nodes // below its views, and each view's context reads across into its `I_r`. #[test] diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index 3025d7c3f..66e4c143d 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -38,19 +38,19 @@ //! computation is multiplied by how often it is computed per second //! ([`NodeCost::cost_per_second`](asap_cost::NodeCost::cost_per_second)): //! -//! * A not-kept node is recomputed for each consumer that reads it +//! * A not-materialized node is recomputed for each consumer that reads it //! and is not stored: it is charged once per consumer //! ([`NodeCost::multiplier`](asap_cost::NodeCost::multiplier)) at the sum of their rates. Its consumers are //! the queries whose sub-DAG reaches it and the materialized nodes above //! it, counted without looking through a materialized node: a node below -//! one is computed when that node is. The consumers kept at ingestion time of +//! one is computed when that node is. The consumers materialized at ingestion time of //! one refresh window (`PhysicalASAPDAG::refresh_window`: for a tumbling window //! chain, its tumbling-window width) are refreshed in one ingestion run and count as //! one consumer: a `Scan` under a KLL chain and a DDSketch chain of 10 s //! tumbling windows is computed once per second of arriving data, under chains of //! 10 s and 60 s tumbling windows twice. Stage 2 keeps a shared node one //! node (it copies it only for readers at two timings). A shared -//! not-kept input costs what reading it separately does (#509 +//! not-materialized input costs what reading it separately does (#509 //! Example 4) only when every consumer reads the same window: a query-time `Scan` is priced over the longest window //! read above it, so each consumer pays for that window, and a scan a 1 m //! and a 5 m window share costs more than two separate scans. Stage 2 @@ -59,7 +59,7 @@ //! * A `OneEvaluation` node is computed once for all the queries that reach //! it, at their combined rate: queries repeating at the same interval are //! evaluated together, so each distinct interval counts once. -//! * A node kept at ingestion time runs as data arrives: it is priced over one +//! * A node materialized at ingestion time runs as data arrives: it is priced over one //! second of arriving rows, once per second, whatever its readers' rates. //! A tumbling-window chain maintained this way updates only its newest //! tumbling window: each arriving row is placed in it and updates it. @@ -70,18 +70,18 @@ //! //! Under cost model 1, memory is charged as bytes held per second //! ([`ResourceUsage::average_memory_bytes`](asap_cost::ResourceUsage::average_memory_bytes)), at -//! `cost_per_memory_byte_second` per byte per second. A node kept at ingestion time +//! `cost_per_memory_byte_second` per byte per second. A node materialized at ingestion time //! node keeps its state every second: twice for a whole window (the window //! being built and the completed one queries read) and `N + 1` tumbling windows for a //! chain of `N` (the `N` the query merges and the one being built). A //! `OneEvaluation` node's state is reused only within one evaluation, so it is //! held only while that evaluation runs: its bytes times the latency of the //! longest query reading it, once per evaluation. A query-time -//! not-kept node's working memory (a sketch being built, an exact +//! not-materialized node's working memory (a sketch being built, an exact //! aggregate's values) is charged once per consumer that recomputes it: //! for a query, its bytes times that query's latency, at its rate; for a //! materialized node reading it (directly or through other -//! not-kept nodes), its bytes times the latency of the longest +//! not-materialized nodes), its bytes times the latency of the longest //! query reading that node, at the node's rate, as a `OneEvaluation` state is. //! A query-time `AcrossEvaluations` tumbling-window chain (#509 Example //! 4's B3, offered by Stage 2 when the deployment keeps query-time results, @@ -99,8 +99,8 @@ //! at 1 min steps): //! //! * every query-time computation that is not kept across evaluations -//! (not kept, `OneEvaluation`) runs once per step, `S` times per -//! request; a kept at ingestion time state is maintained as before, and the +//! (not materialized, `OneEvaluation`) runs once per step, `S` times per +//! request; a materialized at ingestion time state is maintained as before, and the //! merge and estimate over it run once per step; //! * a chain kept across evaluations is built once per request: Stage 2 //! offers it only when the requests repeat at its tumbling-window width, so in the @@ -116,7 +116,7 @@ //! `S = 1` and the retention is the window, so every price is as above. //! Memory a computation holds only while it runs counts in //! [`ResourceUsage::peak_memory_bytes`](asap_cost::ResourceUsage::peak_memory_bytes), which cost models 2 and 3 read, and -//! under cost model 1 for the time it is held, as above. (A not-kept +//! under cost model 1 for the time it is held, as above. (A not-materialized //! node computed at ingestion time is a streaming operator holding one row, //! and is not charged.) //! @@ -330,8 +330,8 @@ mod tests { use asap_cost::analytical::AnalyticalCostError; use asap_cost::execution_demand::evaluation_rate; use asap_cost::state_bytes::{sketch_shape, summary_shape, StateInputRows}; - use asap_cost::{kept_tumbling_window_chains, node_map, plan_cost, NodeMap}; use asap_cost::{lookup, StateFamily}; + use asap_cost::{materialized_tumbling_window_chains, node_map, plan_cost, NodeMap}; use asap_cost::{ CalibrationFit, ClusterLimits, ClusterObjective, CostInputs, CostModel, NodePriceSource, OperatorKind, PlanCost, ResourceUsage, COST_SOURCE, MEASURED_COST_SOURCE, @@ -364,7 +364,7 @@ mod tests { fn self_calibrated_cost( dag: &PhysicalASAPDAG, nodes: &NodeMap<'_>, - kept_chains: &std::collections::HashSet, + materialized_chains: &std::collections::HashSet, recurrence: &[QueryRecurrence], range_evaluations: &[Option], data: &DataWorkload, @@ -374,7 +374,7 @@ mod tests { plan_cost( dag, nodes, - kept_chains, + materialized_chains, recurrence, range_evaluations, data, @@ -396,7 +396,7 @@ mod tests { self_calibrated_cost( dag, &node_map(dag), - &kept_tumbling_window_chains(dag), + &materialized_tumbling_window_chains(dag), recurrence, &[], data, @@ -1116,11 +1116,11 @@ mod tests { } /// Query 1 is `sum(...)` over query 2's output. Every node reached by - /// both queries is not kept, so recomputed for each: charged + /// both queries is not materialized, so recomputed for each: charged /// twice. Materializing query 2's root (`OneEvaluation`) charges it once, /// and the nodes below it once, since they run only when it does. #[test] - fn not_kept_shared_nodes_are_charged_per_query() { + fn not_materialized_shared_nodes_are_charged_per_query() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let mut candidate = optimize_physical_asap( @@ -1171,13 +1171,13 @@ mod tests { assert!(stored.cost_per_second.unwrap() < cost.cost_per_second.unwrap()); } - /// A not-kept node two queries read is computed for each, so + /// A not-materialized node two queries read is computed for each, so /// its working memory is held once per query, each time for that /// query's latency: `bytes · Σ rate_q · latency_q`, not the longest /// latency at both rates. Query 1 is `sum(...)` over query 2's output, /// so it runs longer; they repeat every 10 s and every 20 s. #[test] - fn shared_not_kept_memory_is_held_for_each_reading_query() { + fn shared_not_materialized_memory_is_held_for_each_reading_query() { let outer = lower_promql("sum(sum_over_time(m[1m]))", AccuracyTarget::exact()); let inner = outer.children()[0].clone(); let candidate = optimize_physical_asap( @@ -2424,7 +2424,7 @@ mod tests { } /// `candidates` with every state node (a summary build or an exact - /// aggregate) kept across evaluations, so selection charges its kept + /// aggregate) kept across evaluations, so selection charges its materialized /// bytes every second (a state kept for one evaluation is held only for /// that evaluation). fn keeping_state(mut candidates: Vec) -> Vec { @@ -3420,7 +3420,7 @@ mod tests { } /// `quantile_over_time(0.99, m[1m])` with its KLL candidate chosen, its - /// state kept with `kept` (`None`: not kept). + /// state materialized with `materialized` (`None`: not materialized). fn kll_dag(kept: Option) -> PhysicalASAPDAG { use asap_types::ir::{ apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, @@ -3527,13 +3527,13 @@ mod tests { assert!(range.detail.contains("keep"), "{}", range.detail); } - /// Kept in memory at ingestion time until a query reads it. + /// Materialized in memory at ingestion time until a query reads it. const AT_INGESTION: Option = - Some(PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION); + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION); - /// Kept in memory at query time for one evaluation. + /// Materialized in memory at query time for one evaluation. const AT_QUERY: Option = - Some(PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION); + Some(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION); fn node_of(dag: &PhysicalASAPDAG, pick: impl Fn(&Payload) -> bool) -> PhysicalASAPNodeId { dag.nodes.iter().find(|n| pick(&n.payload)).unwrap().id @@ -3594,7 +3594,7 @@ mod tests { /// every second. At query time the state is reused only within one /// evaluation, so it is held only while that evaluation runs: its bytes /// times the evaluation's latency, once per evaluation. State computed - /// and dropped within a query (not kept) is held while that + /// and dropped within a query (not materialized) is held while that /// query runs too, and charged the same way. #[test] fn kept_state_is_charged_per_byte_per_second() { @@ -3744,7 +3744,7 @@ mod tests { assert!(quantile > 10 * sum, "{quantile} vs {sum}"); } - /// A not-kept node read by two queries is computed for each, at + /// A not-materialized node read by two queries is computed for each, at /// each one's rate; `OneEvaluation`, it is computed once at their combined /// rate, where queries at the same interval run together. #[test] @@ -4821,7 +4821,8 @@ mod tests { .find(|c| { c.dag.nodes.iter().all(|n| match n.payload { Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { .. }) => { - n.output_state.timing == ExecutionTiming::IngestionTime && n.lifetime.is_kept() + n.output_state.timing == ExecutionTiming::IngestionTime + && n.lifetime.is_materialized() } _ => n.lifetime == Lifetime::None, }) @@ -5343,7 +5344,7 @@ mod tests { plan_cost( &candidate.dag, &node_map(&candidate.dag), - &kept_tumbling_window_chains(&candidate.dag), + &materialized_tumbling_window_chains(&candidate.dag), &[repeating(MINUTE)], &[], &arriving(10_000.0), @@ -5574,7 +5575,7 @@ mod tests { let cost = self_calibrated_cost( &candidate.dag, &node_map(&candidate.dag), - &kept_tumbling_window_chains(&candidate.dag), + &materialized_tumbling_window_chains(&candidate.dag), std::slice::from_ref(&recurrence), &[range], &data(), diff --git a/crates/plan-selection/src/milp/decode.rs b/crates/plan-selection/src/milp/decode.rs index 1b9ba8216..c3dddfd60 100644 --- a/crates/plan-selection/src/milp/decode.rs +++ b/crates/plan-selection/src/milp/decode.rs @@ -1,9 +1,9 @@ //! #1095 Step 6 (§2.0, "Decode and check"): the group selection MILP's raw //! solution as a [`DagOfSelectedCandidates`], one node per candidate run. //! -//! - A candidate computed in a context (`p[ctx, c] = 1`, a not-kept +//! - A candidate computed in a context (`p[ctx, c] = 1`, a not-materialized //! query-time candidate in a query's or a shareable candidate's context, -//! or a not-kept ingestion-time candidate in an `I_r`) is one node per +//! or a not-materialized ingestion-time candidate in an `I_r`) is one node per //! context: selected in two contexts, it is two nodes; read by two //! readers in one context, it is one. //! - A selected shareable candidate (`x[m] = 1`) is one node, whoever reads diff --git a/crates/plan-selection/src/milp/model/tests.rs b/crates/plan-selection/src/milp/model/tests.rs index 9e9558de6..41aa35e47 100644 --- a/crates/plan-selection/src/milp/model/tests.rs +++ b/crates/plan-selection/src/milp/model/tests.rs @@ -238,7 +238,7 @@ fn solve_and_check_by( let (plan, _) = plan_cost( plan_dag, &node_map(plan_dag), - &asap_cost::kept_tumbling_window_chains(plan_dag), + &asap_cost::materialized_tumbling_window_chains(plan_dag), &recurrence, &ranges, &fixture.data, @@ -478,7 +478,7 @@ fn a_kept_pane_chain_keeps_the_longest_readers_span() { node.asap(), Some(asap_types::ir::ASAPOp::SummaryTumblingWindowChain { .. }) ) && (candidate.properties.timing() == ExecutionTiming::IngestionTime - && candidate.properties.lifetime().is_kept()) + && candidate.properties.lifetime().is_materialized()) }); require_one_of(milp, &chains); }) @@ -494,11 +494,11 @@ fn a_kept_pane_chain_keeps_the_longest_readers_span() { ); } -// A not-kept input of a `OneEvaluation` candidate both queries read +// A not-materialized input of a `OneEvaluation` candidate both queries read // (`rate(m[5m])` under `sum` and `max`, one schedule group) runs once, in // the candidate's context, and is costed as `plan_cost` costs it. #[test] -fn a_shared_results_not_kept_input_runs_once() { +fn a_shared_results_not_materialized_input_runs_once() { let fixture = through_stages( &[ query("sum(rate(m[5m]))", 60_000), @@ -564,7 +564,7 @@ fn one_ingestion_scan_shared_by_two_sketch_configurations_is_charged_once() { let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { let sketches = candidates_where(milp, |candidate, node| { candidate.properties.timing() == ExecutionTiming::IngestionTime - && candidate.properties.lifetime().is_kept() + && candidate.properties.lifetime().is_materialized() && matches!( node.asap(), Some(asap_types::ir::ASAPOp::SummaryAgg { .. }) @@ -616,7 +616,7 @@ fn ingestion_scans_under_refresh_windows( let checked = solve_and_check(&fixture, &cost_inputs(), |milp| { let states = candidates_where(milp, |candidate, _| { candidate.properties.timing() == ExecutionTiming::IngestionTime - && candidate.properties.lifetime().is_kept() + && candidate.properties.lifetime().is_materialized() }); let window_of = |state: PhysicalCandidateId| { milp.inputs @@ -862,7 +862,7 @@ fn a_phantom_reader_does_not_satisfy_minimum_query_readers() { ); } -// A not-kept query-time candidate selected in two contexts is two +// A not-materialized query-time candidate selected in two contexts is two // nodes; a shareable candidate two queries read is one node. #[test] fn runs_decode_one_node_per_context_and_one_per_shareable_candidate() { @@ -873,7 +873,7 @@ fn runs_decode_one_node_per_context_and_one_per_shareable_candidate() { let unshared = solve_and_check(&fixture, &cost_inputs(), |milp| { let shared = candidates_where(milp, |candidate, _| { candidate.properties.timing() == ExecutionTiming::QueryTime - && candidate.properties.lifetime().is_kept() + && candidate.properties.lifetime().is_materialized() }); forbid(milp, &shared); let ingestion = candidates_where(milp, |candidate, _| { diff --git a/crates/plan-selection/src/select.rs b/crates/plan-selection/src/select.rs index ed5546432..1da0aed75 100644 --- a/crates/plan-selection/src/select.rs +++ b/crates/plan-selection/src/select.rs @@ -25,7 +25,7 @@ use std::collections::BTreeMap; use std::time::Instant; -use asap_cost::{kept_tumbling_window_chains, node_map, plan_cost, CostInputs}; +use asap_cost::{materialized_tumbling_window_chains, node_map, plan_cost, CostInputs}; use asap_types::ir::{ASAPOp, Operator}; use asap_types::stages::{ AssignmentRealizer, DagOfSelectedCandidates, PhysicalASAPMemoCandidates, @@ -128,7 +128,7 @@ pub fn select_plan( let (cost, _) = plan_cost( &plan.dag, &node_map(&plan.dag), - &kept_tumbling_window_chains(&plan.dag), + &materialized_tumbling_window_chains(&plan.dag), &recurrence, &ranges, data, diff --git a/crates/plan-selection/src/selector.rs b/crates/plan-selection/src/selector.rs index 5270385cd..27a818d8f 100644 --- a/crates/plan-selection/src/selector.rs +++ b/crates/plan-selection/src/selector.rs @@ -19,7 +19,8 @@ use crate::report::{ use crate::SelectionModels; use asap_cost::analytical::AnalyticalCostError; use asap_cost::{ - kept_tumbling_window_chains, node_map, plan_cost, query_reach, tumbling_window_retention_ms, + materialized_tumbling_window_chains, node_map, plan_cost, query_reach, + tumbling_window_retention_ms, }; type Ranking = PlanRanking; @@ -180,11 +181,11 @@ impl<'a> PlanSelector<'a> { return Ok(CalibrationFit::default()); } let nodes = node_map(&candidate.dag); - let kept_chains = kept_tumbling_window_chains(&candidate.dag); + let materialized_chains = materialized_tumbling_window_chains(&candidate.dag); let (_, fit) = plan_cost( &candidate.dag, &nodes, - &kept_chains, + &materialized_chains, &self.recurrence, &self.range_evaluations, self.data, @@ -230,12 +231,12 @@ impl<'a> PlanSelector<'a> { } }; let nodes = node_map(&candidate.dag); - let kept_chains = kept_tumbling_window_chains(&candidate.dag); + let materialized_chains = materialized_tumbling_window_chains(&candidate.dag); let settings = self.models.cost_inputs; let (cost, _) = plan_cost( &candidate.dag, &nodes, - &kept_chains, + &materialized_chains, &self.recurrence, &self.range_evaluations, self.data, diff --git a/crates/planner/src/installable.rs b/crates/planner/src/installable.rs index 1160405a6..519e9066f 100644 --- a/crates/planner/src/installable.rs +++ b/crates/planner/src/installable.rs @@ -1000,7 +1000,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &merged, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&merged, &assignment, &mut NodeToTimedNodeCache::new()) @@ -1040,7 +1040,7 @@ mod tests { for node in tumbling_windows.iter().chain([&merge]) { assignment.set( node, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let timed = diff --git a/crates/planner/tests/deployment_accuracy_model.rs b/crates/planner/tests/deployment_accuracy_model.rs index 8edb9f6ec..ad29bd00e 100644 --- a/crates/planner/tests/deployment_accuracy_model.rs +++ b/crates/planner/tests/deployment_accuracy_model.rs @@ -115,7 +115,7 @@ fn physical_candidates( &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(0), // option 0: not kept + &mut |_, _, _| Some(0), // option 0: not materialized ) .unwrap() .expect("query-time fixture is executable"); diff --git a/crates/planner/tests/per_sample_updater.rs b/crates/planner/tests/per_sample_updater.rs index 94af31123..b8f83f1e5 100644 --- a/crates/planner/tests/per_sample_updater.rs +++ b/crates/planner/tests/per_sample_updater.rs @@ -24,7 +24,7 @@ use time_series::{series_identity, series_labels, time_series_tables, RawDataSam const EVALUATION_MS: i64 = 3_600_000; #[tokio::test] -async fn per_sample_updates_build_the_kept_tumbling_window_the_plan_refreshes() { +async fn per_sample_updates_build_the_materialized_tumbling_window_the_plan_refreshes() { // What the user writes: the 5-minute rate of a counter, every minute, // exactly, over 1,000 series sampled every 15 s. let workload: PlanningWorkload = serde_json::from_str( diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index 70250d0aa..bdf428cf3 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -1550,7 +1550,7 @@ impl OptimizationPass for StoredAsForced { } } -/// `node` untimed, with `store`'s kept output (or its own) recorded in +/// `node` untimed, with `store`'s materialized output (or its own) recorded in /// `assignment` for every node of its sub-DAG. fn untime( node: &Rc, @@ -1576,7 +1576,7 @@ fn untime( ASAPOp::SummaryAgg { .. } | ASAPOp::SummaryTumblingWindowChain { .. } | ASAPOp::SummaryMerge { .. }, - ) if node.lifetime.is_kept() => node.physical_properties().map(Result::unwrap), + ) if node.lifetime.is_materialized() => node.physical_properties().map(Result::unwrap), _ => None, }; if let Some(kept) = store(node).or(own) { @@ -1589,13 +1589,13 @@ fn untime( /// Every `SummaryAgg` built at ingestion time. fn summaries_at_ingestion(node: &OperatorNode) -> Option { matches!(node.asap(), Some(ASAPOp::SummaryAgg { .. })) - .then(|| PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION) + .then(|| PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION) } /// Every `SummaryMerge` built at query time and kept across evaluations. fn merges_kept(node: &OperatorNode) -> Option { matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })) - .then(|| PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME) + .then(|| PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME) } /// Exact PromQL `queries`, every minute, over 6 ingesting series of `m` diff --git a/crates/planner/tests/summary_sharing.rs b/crates/planner/tests/summary_sharing.rs index a8bf5ddc4..10fc6ed25 100644 --- a/crates/planner/tests/summary_sharing.rs +++ b/crates/planner/tests/summary_sharing.rs @@ -142,7 +142,7 @@ fn composed_summary_candidates( &entries, data, models.deployment_capabilities.query_time_results_retained, - &mut |_, _, _| Some(0), // option 0: not kept + &mut |_, _, _| Some(0), // option 0: not materialized ) .unwrap() .expect("supported physical computation"); @@ -200,7 +200,7 @@ fn shared_kll_candidate(workload: &PlanningWorkload) -> asap_types::physical::Ph &workload.query_workload.entries().collect::>(), workload.data_workload.as_ref().unwrap(), false, - &mut |_, _, _| Some(0), // option 0: not kept + &mut |_, _, _| Some(0), // option 0: not materialized ) .unwrap() .unwrap(); diff --git a/crates/types/src/ir/materialized_view.rs b/crates/types/src/ir/materialized_view.rs index 8a86a2e18..893938139 100644 --- a/crates/types/src/ir/materialized_view.rs +++ b/crates/types/src/ir/materialized_view.rs @@ -7,7 +7,7 @@ //! //! A **materialized view** is a node whose output is kept across //! evaluations: its lifetime is `AcrossEvaluations`, at ingestion time or -//! at query time, and it carries its `retention_ms`. A node kept for +//! at query time, and it carries its `retention_ms`. A node materialized for //! `OneEvaluation` is not a view: its output is discarded after one //! evaluation. A query-time `Scan` carries how long its source's rows are //! kept for it (`None` when it reads them unbounded). @@ -234,7 +234,7 @@ impl RawDataWindow { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum MaterializedViewRefresh { - /// Refreshed at ingestion time (kept at ingestion time): the runtime runs the + /// Refreshed at ingestion time (materialized at ingestion time): the runtime runs the /// node in an ingestion run once its inputs are complete (its windows' /// samples have arrived and the views it reads are refreshed), and /// keeps the result. diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index d4c8e41a4..c6c5594be 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -95,7 +95,7 @@ impl Operator { /// until a physical properties assignment is applied; export rejects an executable /// node without one. `lifetime` is how long that assignment keeps this /// node's output (`None` until then, and for every node whose output is not -/// kept); with `timing` it is the node's [`crate::physical::PhysicalProperties`]. +/// materialized); with `timing` it is the node's [`crate::physical::PhysicalProperties`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct OperatorNode { pub operator: Operator, diff --git a/crates/types/src/ir/physical_export.rs b/crates/types/src/ir/physical_export.rs index 2afad5382..dd62b88a3 100644 --- a/crates/types/src/ir/physical_export.rs +++ b/crates/types/src/ir/physical_export.rs @@ -28,7 +28,7 @@ use crate::ir::properties::guarantee::AccuracyGuarantee; use crate::ir::properties::timing::{ apply_physical_properties_to_roots, PhysicalPropertiesAssignment, }; -use crate::ir::properties::timing::{data_state, is_keepable_state_output}; +use crate::ir::properties::timing::{data_state, is_materializable_state_output}; use crate::ir::schema::{FieldDataType, Schema}; use crate::physical::{InvalidPhysicalProperties, Lifetime, PhysicalProperties}; @@ -73,7 +73,7 @@ pub struct PhysicalASAPDAGNode { pub output_state: ExecutionDataState, /// How long and where the deployment keeps this node's output: the /// lifetime the physical properties assignment chose for the sub-DAG this - /// node produces. Any node may be kept (#509 §Materialization); a node + /// node produces. Any node may be materialized (#509 §Materialization); a node /// with no assignment has lifetime `None`. With `output_state.timing` it /// is the node's [`PhysicalProperties`]. pub lifetime: Lifetime, @@ -187,10 +187,10 @@ pub enum PhysicalASAPDAGValidationError { #[source] reason: InvalidPhysicalProperties, }, - /// A summary build (or maintained population) that is not kept but does + /// A summary build (or maintained population) that is not materialized but does /// not run at query time: a planner bug. #[error("node {node:?} is a summary build that is not kept but does not run at query time")] - UnkeptSummaryBuildNotAtQueryTime { node: PhysicalASAPNodeId }, + UnmaterializedSummaryBuildNotAtQueryTime { node: PhysicalASAPNodeId }, #[error("ingestion node {consumer:?} depends on query node {producer:?}")] QueryDependencyInIngestion { producer: PhysicalASAPNodeId, @@ -364,7 +364,7 @@ pub enum ReferencePlanError { impl PhysicalASAPDAG { /// This DAG's plan with nothing materialized: the same operators, /// summaries and summary parameters, with every sub-DAG - /// not kept and so every node at query time (the default + /// not materialized and so every node at query time (the default /// [`PhysicalPropertiesAssignment`]). Node ids are renumbered, and `roots` /// and `scalar_roots` keep their order. /// @@ -381,7 +381,7 @@ impl PhysicalASAPDAG { } /// Every node of this DAG as IR, by node id, untimed and - /// not kept with its exported guarantee: what a caller derives + /// not materialized with its exported guarantee: what a caller derives /// IR properties of a plan file's node from, such as its /// [`SummaryCoverage`](crate::ir::properties::summary_coverage::SummaryCoverage). /// Shared inputs stay shared. Validates the DAG first. @@ -423,7 +423,7 @@ impl PhysicalASAPDAG { /// - a `TimeRange(w)`, range or instant: `(T - s - w, T - s]`; /// - a `SummaryTumblingWindowChain` of `n` tumbling windows of width `w`: its whole window `(T - s - /// n·w, T - s]`, or only its newest tumbling window `(T - s - w, T - s]` for a - /// chain in `kept_chains` (kept across evaluations, so each + /// chain in `materialized_chains` (kept across evaluations, so each /// evaluation builds one tumbling window). /// /// `Unbounded` when a root, any other reader, or a shift with an `@` @@ -431,9 +431,9 @@ impl PhysicalASAPDAG { pub fn scan_window( &self, scan: PhysicalASAPNodeId, - kept_chains: &HashSet, + materialized_chains: &HashSet, ) -> ScanWindow { - self.scan_windows([scan], kept_chains)[&scan] + self.scan_windows([scan], materialized_chains)[&scan] } /// [`Self::scan_window`] of each of `scans`, by id, with the DAG @@ -441,7 +441,7 @@ impl PhysicalASAPDAG { pub fn scan_windows( &self, scans: impl IntoIterator, - kept_chains: &HashSet, + materialized_chains: &HashSet, ) -> HashMap { let payloads = self.payloads_by_id(); let mut consumers: HashMap> = HashMap::new(); @@ -473,7 +473,7 @@ impl PhysicalASAPDAG { Some(Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { tumbling_window_width_ms, .. - })) if kept_chains.contains(&consumer) => { + })) if materialized_chains.contains(&consumer) => { u128::from(*tumbling_window_width_ms) } Some(Operator::ASAP(ASAPOp::SummaryTumblingWindowChain { @@ -580,7 +580,7 @@ impl PhysicalASAPDAG { } /// The IR this DAG exports, one root per query in batch order, every - /// node untimed and not kept: the inverse of + /// node untimed and not materialized: the inverse of /// [`compile_physical_asap_workload`] up to `Rc` identity and timing. #[cfg(any(test, feature = "test-support"))] fn untimed_query_roots(&self) -> Result, PhysicalASAPDAGValidationError> { @@ -612,19 +612,19 @@ impl PhysicalASAPDAG { return Err(PhysicalASAPDAGValidationError::DuplicateNodeId(node.id)); } // A node's timing and lifetime must go together; a summary - // build that is not kept runs at query time. Any other node that - // is not kept runs when its consumer runs. + // build that is not materialized runs at query time. Any other node that + // is not materialized runs when its consumer runs. let properties = node.physical_properties().map_err(|reason| { PhysicalASAPDAGValidationError::InvalidPhysicalProperties { node: node.id, reason, } })?; - if is_keepable_state_output(&node.payload) - && properties == PhysicalProperties::NOT_KEPT_AT_INGESTION + if is_materializable_state_output(&node.payload) + && properties == PhysicalProperties::NOT_MATERIALIZED_AT_INGESTION { return Err( - PhysicalASAPDAGValidationError::UnkeptSummaryBuildNotAtQueryTime { + PhysicalASAPDAGValidationError::UnmaterializedSummaryBuildNotAtQueryTime { node: node.id, }, ); diff --git a/crates/types/src/ir/properties/execution_data_state.rs b/crates/types/src/ir/properties/execution_data_state.rs index f7f52ffc4..e132d0109 100644 --- a/crates/types/src/ir/properties/execution_data_state.rs +++ b/crates/types/src/ir/properties/execution_data_state.rs @@ -2,7 +2,7 @@ //! //! [`ExecutionTiming`] says when a node's value is produced (ingestion vs. //! query time); [`ExecutionDataState`] pairs it with the [`DataPrimitive`] -//! the edge carries (raw values vs. summary state). A kept output's +//! the edge carries (raw values vs. summary state). A materialized output's //! [`PhysicalProperties`] are the per-sub-DAG choice a node's timing is //! derived from. The rules that assign //! and check them over a DAG live in [`crate::ir::properties::timing`], which reports @@ -100,7 +100,7 @@ pub enum ExecutionDataStateError { }, /// A summary build at query time over an input (rows or exact-accumulator /// state) produced at ingestion time and not stored there (the input node - /// is not kept at ingestion time): at query time that input no longer exists. + /// is not materialized at ingestion time): at query time that input no longer exists. /// Bad input (a hand-built or candidate-fixed plan), not an internal bug. #[error( "a query-time {edge} reads {operator} output produced at ingestion time that is not \ @@ -135,7 +135,7 @@ pub enum ExecutionDataStateError { }, /// A plan root that runs at ingestion time without being stored there /// (a timing fixed by a candidate builder): no query reads its rows. A - /// root assigned kept at ingestion time is valid; the query reads the stored + /// root assigned materialized at ingestion time is valid; the query reads the stored /// output. #[error( "{operator} root runs at ingestion time but is not kept there: no query reads its \ @@ -186,7 +186,7 @@ pub enum ExecutionDataStateError { /// `SummaryJoin` and `Extension`. #[error("{operator} has no execution timing contract yet")] UnimplementedOperator { operator: &'static str }, - /// A node assigned kept at ingestion time over a sub-DAG that can only run at + /// A node assigned materialized at ingestion time over a sub-DAG that can only run at /// query time (#509 Algorithm 3, line 13). #[error("{operator}: upstream of ingestion-time node not at ingestion time")] UpstreamNotAtIngestion { operator: &'static str }, diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index 21ca9813a..9d9a31168 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -3,25 +3,25 @@ //! edges. //! //! The logical DAG carries no timing. Materialization (#509 -//! §Materialization) decides, for each sub-DAG, whether its output is kept, +//! §Materialization) decides, for each sub-DAG, whether its output is materialized, //! and if so with which [`PhysicalProperties`]: its timing and its //! [`Lifetime`] (#1200). [`PhysicalPropertiesAssignment`] records that per -//! sub-DAG, named by the node whose output would be kept (any node: a +//! sub-DAG, named by the node whose output would be materialized (any node: a //! summary state, a population, or e.g. the tumbling windows of #509 //! Example 4), and [`apply_physical_properties`] expands it into a //! timing and a lifetime on every node: //! //! - `SummaryEstimate` and `EvaluatePopulation` run at query time; -//! - a node assigned a kept output runs at that output's timing. A -//! `SummaryAgg` or `MaintainPopulation` without an assignment is not kept +//! - a node assigned a materialized output runs at that output's timing. A +//! `SummaryAgg` or `MaintainPopulation` without an assignment is not materialized //! and runs at query time. Every node upstream of an ingestion-time node -//! also runs at ingestion time, so a kept ingestion-time output (or an +//! also runs at ingestion time, so a materialized ingestion-time output (or an //! ingestion timing fixed by a candidate builder) over something that can //! only exist at query time is an error //! ([`ExecutionDataStateError::UpstreamNotAtIngestion`]); //! - a PromQL `BinaryOp` over per-series inputs that are not the same series //! rows runs at query time, since maintenance cannot align them; -//! - every other node is not kept (lifetime `None`) and runs when its +//! - every other node is not materialized (lifetime `None`) and runs when its //! consumer runs: everything that feeds an ingestion-time node runs at //! ingestion time, everything above an evaluation at query time. //! @@ -30,9 +30,9 @@ //! timing. An explicit assignment on it that agrees is kept; one that needs //! the other timing is an error //! ([`ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming`]). -//! A root may be kept at ingestion time across evaluations: the query reads +//! A root may be materialized at ingestion time across evaluations: the query reads //! its stored output. A root of rows that runs at ingestion time without -//! being kept there is an error +//! being materialized there is an error //! ([`ExecutionDataStateError::UnstoredIngestionRoot`]). //! //! A node reached from two consumers that need different timings cannot be @@ -45,13 +45,13 @@ //! //! | Consumer | Accepts from an input | //! |---|---| -//! | `SummaryAgg.child`, `SummaryTumblingWindowChain.child` | Rows, or exact-accumulator state, never a query-time value when the state is maintained; a query-time build reads an ingestion-time input (rows or exact-accumulator state) only as a kept at ingestion time input's stored output | +//! | `SummaryAgg.child`, `SummaryTumblingWindowChain.child` | Rows, or exact-accumulator state, never a query-time value when the state is maintained; a query-time build reads an ingestion-time input (rows or exact-accumulator state) only as a materialized at ingestion time input's stored output | //! | `SummaryEstimate.summary_input` | Summary state at either timing | //! | `SummaryMerge.children` | Summary state at either timing; at ingestion time only for a merge at ingestion time | //! | `FinalizeExactAccumulator.child` | Exact-accumulator state | //! | `EvaluatePopulation.child` | A timed `MaintainPopulation` | -//! | `MaintainPopulation.child` | Rows at its own timing matching the population's input; unlike a `NonASAP` consumer, a query-time population does not read a kept at ingestion time input's stored output | -//! | any `NonASAP` consumer | Rows (or exact-accumulator state for a projection-like operator) at the consumer's own timing, or an output kept at ingestion time read at query time; ingestion work never reads a query-time value | +//! | `MaintainPopulation.child` | Rows at its own timing matching the population's input; unlike a `NonASAP` consumer, a query-time population does not read a materialized at ingestion time input's stored output | +//! | any `NonASAP` consumer | Rows (or exact-accumulator state for a projection-like operator) at the consumer's own timing, or an output materialized at ingestion time read at query time; ingestion work never reads a query-time value | use std::collections::HashMap; use std::rc::Rc; @@ -69,11 +69,11 @@ use crate::ir::schema::{DataType, FieldDataType, Schema}; use crate::physical::Medium; use crate::physical::{Lifetime, PhysicalProperties}; -/// Which sub-DAG outputs are kept, and with which timing and lifetime +/// Which sub-DAG outputs are materialized, and with which timing and lifetime /// (#509 §Materialization: "Materialization decides, for each sub-DAG, /// whether its output is stored"). A sub-DAG is named by the node whose -/// output is kept (by identity); any node may be assigned. A node without -/// an assignment is not kept: a summary build or `MaintainPopulation` then +/// output is materialized (by identity); any node may be assigned. A node without +/// an assignment is not materialized: a summary build or `MaintainPopulation` then /// runs at query time, every other node when its consumer runs. `Default` /// keeps nothing. /// @@ -84,7 +84,7 @@ pub struct PhysicalPropertiesAssignment { kept: HashMap<*const OperatorNode, (Rc, PhysicalProperties)>, } -/// Each kept node as its operator kind and address, not its whole sub-DAG. +/// Each materialized node as its operator kind and address, not its whole sub-DAG. impl std::fmt::Debug for PhysicalPropertiesAssignment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let kept: Vec<_> = self @@ -101,10 +101,10 @@ impl std::fmt::Debug for PhysicalPropertiesAssignment { } impl PhysicalPropertiesAssignment { - /// Keep the output of the sub-DAG `node` produces with `kept`'s timing - /// and lifetime. `kept` must keep the output (lifetime not `None`). + /// Keep the output of the sub-DAG `node` produces with `materialized`'s timing + /// and lifetime. `materialized` must keep the output (lifetime not `None`). pub fn set(&mut self, node: &Rc, kept: PhysicalProperties) { - debug_assert!(kept.lifetime().is_kept(), "{kept:?} does not keep"); + debug_assert!(kept.lifetime().is_materialized(), "{kept:?} does not keep"); self.kept.insert(Rc::as_ptr(node), (Rc::clone(node), kept)); } @@ -117,10 +117,10 @@ impl PhysicalPropertiesAssignment { } /// Every summary build and `MaintainPopulation` reachable from `roots` - /// kept in memory at ingestion time where the DAG allows it: not under a + /// materialized in memory at ingestion time where the DAG allows it: not under a /// filter, and with nothing below it that can only run at query time. #[cfg(any(test, feature = "test-support"))] - pub fn kept_at_ingestion_where_allowed(roots: &[Rc]) -> Self { + pub fn materialized_at_ingestion_where_allowed(roots: &[Rc]) -> Self { fn visit( node: &Rc, assignment: &mut PhysicalPropertiesAssignment, @@ -133,7 +133,7 @@ impl PhysicalPropertiesAssignment { visit(child, assignment, visited); } if node.timing.is_none() - && is_keepable_state_output(&node.operator) + && is_materializable_state_output(&node.operator) && !is_filtered_build(node) && !node .children() @@ -142,7 +142,7 @@ impl PhysicalPropertiesAssignment { { assignment.set( node, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } } @@ -154,14 +154,14 @@ impl PhysicalPropertiesAssignment { assignment } - /// How `node` is kept, if it is. + /// How `node` is materialized, if it is. fn get(&self, node: &OperatorNode) -> Option { self.kept .get(&(node as *const OperatorNode)) .map(|(_, kept)| *kept) } - /// How `node` is kept, checked against what is below it: + /// How `node` is materialized, checked against what is below it: /// `upstream_at_query_time` says whether something below it can only /// run at query time. fn resolve( @@ -204,7 +204,7 @@ fn timed_properties( /// Whether `operator`'s output is a sub-DAG output that materialization may /// store: a `SummaryAgg`, a `SummaryTumblingWindowChain` or a `MaintainPopulation`. -pub(crate) fn is_keepable_state_output(operator: &Operator) -> bool { +pub(crate) fn is_materializable_state_output(operator: &Operator) -> bool { matches!( operator, Operator::ASAP( @@ -298,11 +298,12 @@ fn forces_query_time( Operator::ASAP(ASAPOp::SummaryEstimate { .. }) | Operator::ASAP(ASAPOp::EvaluatePopulation { .. }) => true, _ if node.timing.is_none() - && (is_keepable_state_output(&node.operator) || assignment.get(node).is_some()) => + && (is_materializable_state_output(&node.operator) + || assignment.get(node).is_some()) => { let upstream = upstream(seen); match assignment.resolve(node, upstream) { - Ok(None) if !is_keepable_state_output(&node.operator) => upstream, + Ok(None) if !is_materializable_state_output(&node.operator) => upstream, Ok(None) => true, Ok(Some(kept)) => kept.timing() == ExecutionTiming::QueryTime, Err(_) => true, @@ -383,9 +384,9 @@ pub fn apply_physical_properties_to_roots( .collect() } -/// Validate the sub-DAG below `root` with every sub-DAG kept at ingestion time +/// Validate the sub-DAG below `root` with every sub-DAG materialized at ingestion time /// where the DAG allows it -/// ([`PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed`]) and +/// ([`PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed`]) and /// `root` consumed at `root_timing`. For planning-time legality checks of a /// candidate before it is assembled into a workload DAG: a candidate must stay /// executable if materialization later puts its states at ingestion time. @@ -395,15 +396,16 @@ pub fn validate_at_ingestion( root: &Rc, root_timing: ExecutionTiming, ) -> Result<(), ExecutionDataStateError> { - let assignment = - PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(root)); + let assignment = PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(root), + ); let mut cache = NodeToTimedNodeCache::new(); let mut forced = HashMap::new(); let timed = write(root, root_timing, &assignment, &mut cache, &mut forced)?; validate(&timed, &mut HashMap::new()) } -/// The data state `node` produces with every sub-DAG kept at ingestion time where +/// The data state `node` produces with every sub-DAG materialized at ingestion time where /// the DAG allows it, when its consumer runs at `consumer` — the planning-time answer to /// "what does this candidate's output look like", consistent with /// [`validate_at_ingestion`]. @@ -413,8 +415,9 @@ pub fn planned_data_state( consumer: ExecutionTiming, ) -> ExecutionDataState { let mut forced = HashMap::new(); - let assignment = - PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(node)); + let assignment = PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(node), + ); let (timing, _) = placement(node, consumer, &assignment, &mut forced) .expect("an assignment kept where allowed never fails"); ExecutionDataState { @@ -476,11 +479,13 @@ fn placement( Some(kept) => (ExecutionTiming::QueryTime, kept.lifetime()), None => (ExecutionTiming::QueryTime, Lifetime::None), }, - _ if is_keepable_state_output(&node.operator) || assignment.get(node).is_some() => { + _ if is_materializable_state_output(&node.operator) || assignment.get(node).is_some() => { let upstream = upstream_at_query_time(forced); match assignment.resolve(node, upstream)? { - None if !is_keepable_state_output(&node.operator) => (consumer, Lifetime::None), - // A summary build that is not kept runs at query time. + None if !is_materializable_state_output(&node.operator) => { + (consumer, Lifetime::None) + } + // A summary build that is not materialized runs at query time. None => (ExecutionTiming::QueryTime, Lifetime::None), Some(kept) => (kept.timing(), kept.lifetime()), } @@ -1012,19 +1017,19 @@ mod tests { ) } - /// Apply with every sub-DAG kept at ingestion time where the DAG allows it, the + /// Apply with every sub-DAG materialized at ingestion time where the DAG allows it, the /// placement whose edge rules these tests exercise. fn apply(root: &Rc) -> Result, ExecutionDataStateError> { apply_physical_properties( root, - &PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref( - root, - )), + &PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(root), + ), &mut NodeToTimedNodeCache::new(), ) } - const KEPT_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); + const MATERIALIZED_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> PhysicalProperties { PhysicalProperties::new(timing, lifetime).unwrap() @@ -1034,11 +1039,11 @@ mod tests { Rc::clone(node.children()[0]) } - /// Without a materialization decision, a summary is not kept and + /// Without a materialization decision, a summary is not materialized and /// it and its input run at query time; an explicit choice overrides the /// default and is recorded on the timed node. #[test] - fn default_assignment_keeps_nothing() { + fn default_assignment_materializes_nothing() { let summary = agg(scan(), kll()); let root = apply_physical_properties( &summary, @@ -1059,7 +1064,7 @@ mod tests { Some(ExecutionDataState::QUERY_ROWS) ); for (lifetime, timing) in [ - (KEPT_ACROSS, ExecutionTiming::IngestionTime), + (MATERIALIZED_ACROSS, ExecutionTiming::IngestionTime), ( Lifetime::OneEvaluation(Medium::Disk), ExecutionTiming::QueryTime, @@ -1077,7 +1082,7 @@ mod tests { } } - /// #509 Algorithm 3, line 13: an explicit assignment kept at ingestion time over a state + /// #509 Algorithm 3, line 13: an explicit assignment materialized at ingestion time over a state /// that only exists at query time is an error, not a silent move to /// query time. #[test] @@ -1087,7 +1092,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &outer, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assert_eq!( apply_physical_properties( @@ -1102,12 +1107,12 @@ mod tests { ); assignment.set( &inner, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let outer = agg(Rc::clone(&inner), kll()); assignment.set( &outer, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let root = apply_physical_properties( &estimate(outer), @@ -1115,8 +1120,8 @@ mod tests { &mut NodeToTimedNodeCache::new(), ) .unwrap(); - assert_eq!(child(&root).lifetime, KEPT_ACROSS); - assert_eq!(child(&child(&root)).lifetime, KEPT_ACROSS); + assert_eq!(child(&root).lifetime, MATERIALIZED_ACROSS); + assert_eq!(child(&child(&root)).lifetime, MATERIALIZED_ACROSS); } #[test] @@ -1219,7 +1224,7 @@ mod tests { } /// A finalize pinned to ingestion time (as fixed-window rate candidates - /// build it) over a state that is not kept at ingestion time names the missing + /// build it) over a state that is not materialized at ingestion time names the missing /// upstream, not an illegal edge. #[test] fn ingestion_pinned_finalize_over_query_time_state_is_upstream_not_at_ingestion() { @@ -1248,18 +1253,18 @@ mod tests { /// at ingestion time are read by a query-time consumer, and a node that /// can only run at query time cannot be stored at ingestion time. #[test] - fn any_node_may_be_kept() { + fn any_node_may_be_materialized() { let tumbling_windows = max(scan()); let root = max(Rc::clone(&tumbling_windows)); let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &tumbling_windows, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).lifetime, KEPT_ACROSS); + assert_eq!(child(&timed).lifetime, MATERIALIZED_ACROSS); assert_eq!(child(&timed).timing, Some(ExecutionTiming::IngestionTime)); assert_eq!( child(&child(&timed)).timing, @@ -1270,7 +1275,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &over_evaluation, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assert_eq!( apply_physical_properties( @@ -1287,7 +1292,7 @@ mod tests { /// A summary build with a filter never runs at ingestion time: an /// ingestion-time build reads raw data samples, which carry none of the - /// query's columns the filter reads. An explicit assignment kept at ingestion time is an + /// query's columns the filter reads. An explicit assignment materialized at ingestion time is an /// error; the all-at-ingestion default leaves it at query time. #[test] fn a_filtered_summary_build_never_runs_at_ingestion_time() { @@ -1322,7 +1327,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &filtered, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assert_eq!( apply_physical_properties( @@ -1382,11 +1387,11 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &state, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assignment.set( &read, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assert_eq!( apply_physical_properties(&read, &assignment, &mut NodeToTimedNodeCache::new()).err(), @@ -1394,7 +1399,8 @@ mod tests { ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: "FinalizeExactAccumulator", fixed: ExecutionTiming::QueryTime, - assigned: PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + assigned: + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, } ) ); @@ -1407,7 +1413,7 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &agg(scan(), kll()), - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let text = format!("{assignment:?}"); assert!(text.contains("SummaryAgg@"), "{text}"); @@ -1463,13 +1469,13 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &rows, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).lifetime, KEPT_ACROSS); + assert_eq!(child(&timed).lifetime, MATERIALIZED_ACROSS); } /// The same holds for exact-accumulator state: a query-time build cannot @@ -1496,13 +1502,13 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &state, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); - assert_eq!(child(&timed).lifetime, KEPT_ACROSS); + assert_eq!(child(&timed).lifetime, MATERIALIZED_ACROSS); } /// A node placed at ingestion time with a lifetime that cannot go with @@ -1585,28 +1591,31 @@ mod tests { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &root, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); - assert_eq!(exported(&timed, "Aggregate"), KEPT_ACROSS); + assert_eq!(exported(&timed, "Aggregate"), MATERIALIZED_ACROSS); let state = agg(scan(), exact_sum()); let root = finalize(Rc::clone(&state)); let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &state, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); assignment.set( &root, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&root, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::IngestionTime)); - assert_eq!(exported(&timed, "FinalizeExactAccumulator"), KEPT_ACROSS); + assert_eq!( + exported(&timed, "FinalizeExactAccumulator"), + MATERIALIZED_ACROSS + ); let root = placed_at_ingestion(max(scan())); assert_eq!( diff --git a/crates/types/src/physical/properties.rs b/crates/types/src/physical/properties.rs index f3cc9f658..2fc33a305 100644 --- a/crates/types/src/physical/properties.rs +++ b/crates/types/src/physical/properties.rs @@ -5,21 +5,21 @@ //! |---|---|---| //! | query | `None` | in each evaluation that reads it; discarded after its reader | //! | query | `OneEvaluation` | once per evaluation; its readers in that evaluation share it | -//! | query | `AcrossEvaluations` | at query time, kept for later evaluations (a tumbling-window chain that builds its newest window each evaluation) | +//! | query | `AcrossEvaluations` | at query time, materialized for later evaluations (a tumbling-window chain that builds its newest window each evaluation) | //! | ingestion | `None` | as data arrives, inside the ingestion work that reads it | //! | ingestion | `AcrossEvaluations` | as data arrives; kept until a query reads it | //! | ingestion | `OneEvaluation` | invalid: there is no evaluation at ingestion time | use crate::ir::properties::ExecutionTiming; -/// Where a kept output is stored. +/// Where a materialized output is stored. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub enum Medium { Memory, Disk, } -/// How long a node's output lives. Only a kept output has a medium. +/// How long a node's output lives. Only a materialized output has a medium. #[derive( Default, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, )] @@ -36,7 +36,7 @@ pub enum Lifetime { impl Lifetime { /// Whether the output outlives its reader: `OneEvaluation` or /// `AcrossEvaluations`. - pub fn is_kept(self) -> bool { + pub fn is_materialized(self) -> bool { self != Self::None } @@ -63,29 +63,29 @@ pub struct PhysicalProperties { } impl PhysicalProperties { - /// Query time, not kept: runs in each reader's execution. - pub const NOT_KEPT_AT_QUERY_TIME: Self = Self { + /// Query time, not materialized: runs in each reader's execution. + pub const NOT_MATERIALIZED_AT_QUERY_TIME: Self = Self { timing: ExecutionTiming::QueryTime, lifetime: Lifetime::None, }; - /// Ingestion time, not kept: runs inside the ingestion work that reads it. - pub const NOT_KEPT_AT_INGESTION: Self = Self { + /// Ingestion time, not materialized: runs inside the ingestion work that reads it. + pub const NOT_MATERIALIZED_AT_INGESTION: Self = Self { timing: ExecutionTiming::IngestionTime, lifetime: Lifetime::None, }; - /// Query time, kept in memory until the evaluation's readers finish. - pub const KEPT_IN_MEMORY_FOR_ONE_EVALUATION: Self = Self { + /// Query time, materialized in memory until the evaluation's readers finish. + pub const MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION: Self = Self { timing: ExecutionTiming::QueryTime, lifetime: Lifetime::OneEvaluation(Medium::Memory), }; - /// Ingestion time, kept in memory until a query reads it. - pub const KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION: Self = Self { + /// Ingestion time, materialized in memory until a query reads it. + pub const MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION: Self = Self { timing: ExecutionTiming::IngestionTime, lifetime: Lifetime::AcrossEvaluations(Medium::Memory), }; - /// Query time, kept in memory across evaluations (a tumbling-window chain + /// Query time, materialized in memory across evaluations (a tumbling-window chain /// that builds its newest window at each evaluation). - pub const KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME: Self = Self { + pub const MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME: Self = Self { timing: ExecutionTiming::QueryTime, lifetime: Lifetime::AcrossEvaluations(Medium::Memory), }; @@ -112,7 +112,7 @@ impl PhysicalProperties { } /// Whether a reader running at `reader` may read this output: one at the - /// same timing, or a query-time reader of an ingestion-time output kept + /// same timing, or a query-time reader of an ingestion-time output materialized /// until a query reads it. pub fn readable_at(self, reader: ExecutionTiming) -> bool { reader == self.timing @@ -156,11 +156,11 @@ mod tests { #[test] fn named_properties_are_valid() { for named in [ - PhysicalProperties::NOT_KEPT_AT_QUERY_TIME, - PhysicalProperties::NOT_KEPT_AT_INGESTION, - PhysicalProperties::KEPT_IN_MEMORY_FOR_ONE_EVALUATION, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + PhysicalProperties::NOT_MATERIALIZED_AT_QUERY_TIME, + PhysicalProperties::NOT_MATERIALIZED_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, ] { assert_eq!( PhysicalProperties::new(named.timing(), named.lifetime()), @@ -170,7 +170,7 @@ mod tests { } #[test] - fn a_query_time_reader_reads_only_a_kept_ingestion_output() { + fn a_query_time_reader_reads_only_a_materialized_ingestion_output() { let at = |timing, lifetime| PhysicalProperties::new(timing, lifetime).unwrap(); let query = ExecutionTiming::QueryTime; let ingestion = ExecutionTiming::IngestionTime; diff --git a/crates/types/src/physical/workload_plan.rs b/crates/types/src/physical/workload_plan.rs index 97d230160..c27a5439c 100644 --- a/crates/types/src/physical/workload_plan.rs +++ b/crates/types/src/physical/workload_plan.rs @@ -7,7 +7,7 @@ use crate::ir::QueryRoot; /// display labels are derived from it by the devtools. #[derive(Debug, Clone)] pub struct PhysicalWorkloadPlan { - /// `P` (nothing kept) or `P-m`, set by the caller. + /// `P` (nothing materialized) or `P-m`, set by the caller. pub id: String, /// The id of the logical candidate it implements. pub from_logical: String, @@ -18,10 +18,13 @@ pub struct PhysicalWorkloadPlan { } impl PhysicalWorkloadPlan { - /// Whether any node of `dag` is kept: a summary build, or a shared + /// Whether any node of `dag` is materialized: a summary build, or a shared /// non-summary node built once per evaluation. #[cfg(any(test, feature = "test-support"))] - pub fn keeps_any(&self) -> bool { - self.dag.nodes.iter().any(|node| node.lifetime.is_kept()) + pub fn materializes_any(&self) -> bool { + self.dag + .nodes + .iter() + .any(|node| node.lifetime.is_materialized()) } } diff --git a/crates/types/src/stages/physical/memo_candidates.rs b/crates/types/src/stages/physical/memo_candidates.rs index 3075467cb..88e7882f9 100644 --- a/crates/types/src/stages/physical/memo_candidates.rs +++ b/crates/types/src/stages/physical/memo_candidates.rs @@ -65,7 +65,7 @@ impl OperatorNodeOfCandidateForMemoGroup { pub struct PhysicalCandidate { /// The operator node it runs. pub operator_node: OperatorNodeOfCandidateForMemoGroupId, - /// When it runs and how long its result lives. A node that is not kept + /// When it runs and how long its result lives. A node that is not materialized /// under an ingestion-time build still runs at ingestion time. pub properties: PhysicalProperties, /// Per input of its operator node (in `map_children` order), the @@ -77,7 +77,7 @@ pub struct PhysicalCandidate { pub may_produce_query_output: bool, /// One entry per workload query: whether this tumbling-window chain may be kept /// across evaluations when that query is its only reader. Filled only - /// for a query-time tumbling-window chain kept `AcrossEvaluations(Memory)` in a + /// for a query-time tumbling-window chain materialized `AcrossEvaluations(Memory)` in a /// deployment that keeps query-time results; empty otherwise. pub may_keep_across_evaluations_per_sole_reader_query: Vec, } diff --git a/crates/types/tests/materialized_view.rs b/crates/types/tests/materialized_view.rs index b438038fd..952f92da5 100644 --- a/crates/types/tests/materialized_view.rs +++ b/crates/types/tests/materialized_view.rs @@ -95,12 +95,12 @@ fn tumbling_windows_and_kept_merge() -> (PhysicalASAPDAG, usize) { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } assignment.set( &merge, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME, ); let timed = apply_physical_properties(&merge, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); @@ -233,7 +233,7 @@ fn three_chains_over_one_scan() -> (PhysicalASAPDAG, PhysicalASAPDAG) { .map(|chain| { assignment.set( chain, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); QueryRoot::Operator( OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryMerge { @@ -371,7 +371,7 @@ fn a_shifted_tumbling_window_has_its_own_phase() { for tumbling_window in &tumbling_windows { assignment.set( tumbling_window, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let roots: Vec = tumbling_windows @@ -418,7 +418,7 @@ fn views_of_unbounded_windows_are_groups_of_their_own() { .unwrap(); assignment.set( &build, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); QueryRoot::Operator(build) }) @@ -451,7 +451,7 @@ fn a_view_reading_a_view_of_its_group_follows_it() { for view in [&tumbling_window, &rollup] { assignment.set( view, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); } let timed = @@ -504,7 +504,7 @@ fn a_view_has_its_refresh_window_on_a_dag_without_edges() { let mut assignment = PhysicalPropertiesAssignment::default(); assignment.set( &view, - PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, ); let timed = apply_physical_properties(&view, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); diff --git a/crates/types/tests/physical_export.rs b/crates/types/tests/physical_export.rs index dcbdc8c6d..3a84d10ec 100644 --- a/crates/types/tests/physical_export.rs +++ b/crates/types/tests/physical_export.rs @@ -45,7 +45,7 @@ fn plan() -> Rc { const ON_DISK: Lifetime = Lifetime::AcrossEvaluations(Medium::Disk); -/// `plan()` timed with its summary kept at ingestion time on disk. +/// `plan()` timed with its summary materialized at ingestion time on disk. fn timed_at_ingestion() -> Rc { let root = plan(); let mut assignment = PhysicalPropertiesAssignment::default(); @@ -96,7 +96,7 @@ fn query_time_input_to_ingestion_is_rejected() { } /// A node's timing and lifetime must go together: an ingestion-time output -/// cannot be kept for one evaluation, and a summary build that is not kept +/// cannot be kept for one evaluation, and a summary build that is not materialized /// runs at query time. #[test] fn invalid_physical_properties_are_rejected() { @@ -112,7 +112,7 @@ fn invalid_physical_properties_are_rejected() { dag.nodes[1].lifetime = Lifetime::None; assert_eq!( dag.validate(), - Err(PhysicalASAPDAGValidationError::UnkeptSummaryBuildNotAtQueryTime { node: 1 }) + Err(PhysicalASAPDAGValidationError::UnmaterializedSummaryBuildNotAtQueryTime { node: 1 }) ); dag.nodes[1].lifetime = ON_DISK; dag.validate().unwrap(); @@ -386,8 +386,9 @@ fn exports_summary_over_summary_as_typed_precompute_edges() { })) .unwrap(); let mut cache = NodeToTimedNodeCache::new(); - let at_ingestion = - PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(&root)); + let at_ingestion = PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(&root), + ); let timed = apply_physical_properties(&root, &at_ingestion, &mut cache).unwrap(); let compiled = compile_physical_asap_dag_with_node_ids(&timed).unwrap(); assert_eq!(compiled.node_ids.node_id(&timed), Some(3)); diff --git a/crates/types/tests/schema_rebuilding.rs b/crates/types/tests/schema_rebuilding.rs index 80282540f..f9bc36032 100644 --- a/crates/types/tests/schema_rebuilding.rs +++ b/crates/types/tests/schema_rebuilding.rs @@ -333,7 +333,7 @@ fn a_current_series_population_matches_only_its_selectors_lookback() { } /// Population timing is a materialization choice: the population follows its -/// assignment (not kept by default), while its evaluation always +/// assignment (not materialized by default), while its evaluation always /// runs at query time. #[test] fn population_timing_follows_its_physical_properties() { diff --git a/crates/types/tests/summary_merge_structure.rs b/crates/types/tests/summary_merge_structure.rs index 0a6adbf7c..931414247 100644 --- a/crates/types/tests/summary_merge_structure.rs +++ b/crates/types/tests/summary_merge_structure.rs @@ -719,7 +719,7 @@ fn summary_merge_timing() { timings(&PhysicalPropertiesAssignment::default()), (QueryTime, vec![QueryTime, QueryTime]) ); - let at_ingestion = PhysicalProperties::KEPT_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION; + let at_ingestion = PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION; let mut stored_tumbling_windows = PhysicalPropertiesAssignment::default(); for tumbling_window in &tumbling_windows { stored_tumbling_windows.set(tumbling_window, at_ingestion); @@ -735,8 +735,9 @@ fn summary_merge_timing() { assert!( apply_physical_properties(&root, &only_merge, &mut NodeToTimedNodeCache::new()).is_err() ); - let mut stored_merge = - PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(std::slice::from_ref(&root)); + let mut stored_merge = PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed( + std::slice::from_ref(&root), + ); stored_merge.set(&root, at_ingestion); assert_eq!( timings(&stored_merge), diff --git a/crates/types/tests/tumbling_window_chain.rs b/crates/types/tests/tumbling_window_chain.rs index b218de6a2..8585d7022 100644 --- a/crates/types/tests/tumbling_window_chain.rs +++ b/crates/types/tests/tumbling_window_chain.rs @@ -178,7 +178,7 @@ fn expansion_merges_the_tumbling_windows() { /// tumbling windows: a chain materialized at ingestion time expands into tumbling windows each /// built and stored at ingestion time, over ranges and shifts that run at /// ingestion time too, while the merge reading them stays at query time. -/// An not_kept chain expands into query-time tumbling windows. +/// An not_materialized chain expands into query-time tumbling windows. #[test] fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { use asap_types::ir::properties::ExecutionTiming; @@ -186,9 +186,9 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; use asap_types::physical::{Lifetime, Medium, PhysicalProperties}; - let kept_across = Lifetime::AcrossEvaluations(Medium::Memory); + let materialized_across = Lifetime::AcrossEvaluations(Medium::Memory); for (lifetime, timing) in [ - (kept_across, ExecutionTiming::IngestionTime), + (materialized_across, ExecutionTiming::IngestionTime), (Lifetime::None, ExecutionTiming::QueryTime), ] { let chain = chain(shifted(scan(), MINUTE as i64)); @@ -198,7 +198,7 @@ fn expansion_carries_the_chains_timing_onto_its_tumbling_windows() { })) .unwrap(); let mut assignment = PhysicalPropertiesAssignment::default(); - if lifetime.is_kept() { + if lifetime.is_materialized() { assignment.set(&chain, PhysicalProperties::new(timing, lifetime).unwrap()); } let timed = diff --git a/docs/design_docs/architecture/physical-plan-integration.md b/docs/design_docs/architecture/physical-plan-integration.md index 62f1542f1..4d42aaab9 100644 --- a/docs/design_docs/architecture/physical-plan-integration.md +++ b/docs/design_docs/architecture/physical-plan-integration.md @@ -463,7 +463,7 @@ candidate completeness; that evidence belongs to the semi-join's pruning step. The logical DAG carries no execution layout: `apply_physical_properties` writes each node's timing and lifetime from a -`PhysicalPropertiesAssignment` before export (no sub-DAG kept by default, so all +`PhysicalPropertiesAssignment` before export (no sub-DAG materialized by default, so all query time). The exported DAG carries both, and the deployment executes it as given; this is not a claim that every deployment has implemented every placement. diff --git a/docs/design_docs/architecture/planner-runtime-contract.md b/docs/design_docs/architecture/planner-runtime-contract.md index 8b5d16321..dbab5b3cc 100644 --- a/docs/design_docs/architecture/planner-runtime-contract.md +++ b/docs/design_docs/architecture/planner-runtime-contract.md @@ -14,7 +14,7 @@ execution remain downstream. The | Layer | Owner | Examples | |---|---|---| | Logical candidate semantics | ASAPPlanner | Query rewrite; summary family and parameters; grouping; accuracy guarantees when established. | -| Summary materialization and realization selection | ASAPPlanner Stage 2 materialization (#509) | a timing and a lifetime per sub-DAG (`None`, `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and how much a kept output retains; direct build or incremental update; window implementations compared using provider evidence. | +| Summary materialization and realization selection | ASAPPlanner Stage 2 materialization (#509) | a timing and a lifetime per sub-DAG (`None`, `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and how much a materialized output retains; direct build or incremental update; window implementations compared using provider evidence. | | Concrete implementation and deployment | ASAPQuery-backend and its workload optimizer | Library and data-structure implementation, exact tumbling-window layout, placement, sharding, storage, transmission, materialization IDs, executor configuration, and workload-wide assignment. | ASAPCollector and the ASAPQuery data plane execute the compiled downstream diff --git a/docs/design_docs/concepts/glossary.md b/docs/design_docs/concepts/glossary.md index 376a0736e..b31026963 100644 --- a/docs/design_docs/concepts/glossary.md +++ b/docs/design_docs/concepts/glossary.md @@ -38,7 +38,7 @@ A concrete execution and deployment choice: runtime topology of data lifecycle s ## Materialized view -A node of the physical DAG whose output is kept across evaluations (lifetime `AcrossEvaluations`, at ingestion time or at query time), with how long it is kept (`retention_ms` on the node). A node kept for `OneEvaluation` is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. +A node of the physical DAG whose output is kept across evaluations (lifetime `AcrossEvaluations`, at ingestion time or at query time), with how long it is materialized (`retention_ms` on the node). A node materialized for `OneEvaluation` is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. ## Raw data sample diff --git a/docs/design_docs/concepts/post-asap-ir.md b/docs/design_docs/concepts/post-asap-ir.md index 1b4964c95..224c6f3e4 100644 --- a/docs/design_docs/concepts/post-asap-ir.md +++ b/docs/design_docs/concepts/post-asap-ir.md @@ -111,41 +111,41 @@ not definitions of the operator. The logical DAG carries no timing: `OperatorNode::timing` is `None` on every front-end node and every candidate, and `map_children` clears it. Materialization ([#509 §Materialization](../proposals/planner-layering.md#materialization)) -decides, for each sub-DAG, whether its output is kept, and if so with which +decides, for each sub-DAG, whether its output is materialized, and if so with which [`PhysicalProperties`](../../../crates/types/src/physical/properties.rs): a timing and a `Lifetime` (#1200). The lifetime is `None` (discarded after its reader), `OneEvaluation(medium)` (kept until every reader of one evaluation -finishes) or `AcrossEvaluations(medium)` (kept for later evaluations), with -`Medium::Memory` or `Medium::Disk`; an ingestion-time output cannot be kept +finishes) or `AcrossEvaluations(medium)` (materialized for later evaluations), with +`Medium::Memory` or `Medium::Disk`; an ingestion-time output cannot be materialized for `OneEvaluation`. A [`PhysicalPropertiesAssignment`](../../../crates/types/src/ir/properties/timing.rs) records, -per sub-DAG, the properties of its kept output, named by the node whose output -would be kept. Any node may be named: a summary state, a population, or, as in +per sub-DAG, the properties of its materialized output, named by the node whose output +would be materialized. Any node may be named: a summary state, a population, or, as in #509 Example 4, the tumbling windows a query reads. `set(node, Some(properties))` -keeps one, `set(node, None)` keeps none, and every other sub-DAG is not kept. +keeps one, `set(node, None)` keeps none, and every other sub-DAG is not materialized. Stage 2 chooses the assignment. `apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache)` then writes a timing and a lifetime into every node, top-down: - `SummaryEstimate` and `EvaluatePopulation` run at query time; -- a node assigned a kept output runs at that output's timing; a `SummaryAgg` - or `MaintainPopulation` that is not kept runs at query time. Every node - upstream of an ingestion-time node also runs at ingestion time, so a kept +- a node assigned a materialized output runs at that output's timing; a `SummaryAgg` + or `MaintainPopulation` that is not materialized runs at query time. Every node + upstream of an ingestion-time node also runs at ingestion time, so a materialized ingestion-time output over something that can only exist at query time (an - evaluation, or a state not kept at ingestion time) fails with + evaluation, or a state not materialized at ingestion time) fails with `ExecutionDataStateError::UpstreamNotAtIngestion` ("upstream of ingestion-time node not at ingestion time"); -- every other node is not kept and runs when its consumer runs: everything +- every other node is not materialized and runs when its consumer runs: everything that feeds an ingestion-time node runs at ingestion time, everything above an evaluation at query time. A query-time consumer reads the stored output - of a node kept at ingestion time (`AcrossEvaluations`). + of a node materialized at ingestion time (`AcrossEvaluations`). A node whose timing a candidate builder fixed (the query-time `FinalizeExactAccumulator` read boundary of `finalize_query_candidate`) keeps it: an explicit assignment that agrees with that timing is kept, and one that needs the other timing fails with `ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming`; an -explicit kept output is never silently moved or dropped. A root may be kept +explicit materialized output is never silently moved or dropped. A root may be materialized at ingestion time, and the query reads its stored output; a root of rows that runs at ingestion time without being stored there fails with `ExecutionDataStateError::UnstoredIngestionRoot`. @@ -155,17 +155,17 @@ The pass then validates every edge (rows or exact-accumulator state into a an `EvaluatePopulation`, no ingestion work reading a query-time value) and rejects a node reached from two consumers that need different timings; `split_shared_by_timing` copies such a sub-DAG for one side before the -assignment is applied. How much a kept output retains (retention) is decided +assignment is applied. How much a materialized output retains (retention) is decided later and is not in the assignment. -A node the assignment does not set is not kept. The test helper -`PhysicalPropertiesAssignment::kept_at_ingestion_where_allowed(roots)` +A node the assignment does not set is not materialized. The test helper +`PhysicalPropertiesAssignment::materialized_at_ingestion_where_allowed(roots)` (feature `test-support`) sets every `SummaryAgg`, `SummaryTumblingWindowChain` -and `MaintainPopulation` kept at ingestion time where the DAG allows it (not +and `MaintainPopulation` materialized at ingestion time where the DAG allows it (not filtered, nothing below it that can only run at query time). The test helpers `validate_at_ingestion` and `planned_data_state` use it to check, at planning time and without keeping anything, that a candidate stays valid -when every sub-DAG is kept at ingestion time. +when every sub-DAG is materialized at ingestion time. ## Exported DAG @@ -200,8 +200,8 @@ children as edges and no embedded sub-DAGs: Each node also records its `lifetime`, including the medium, so the deployment knows which outputs to keep, for how long and where; validation rejects a timing and lifetime that cannot go together (an ingestion-time -output kept for `OneEvaluation`) and a `SummaryAgg` or `MaintainPopulation` -that is not kept outside query time +output materialized for `OneEvaluation`) and a `SummaryAgg` or `MaintainPopulation` +that is not materialized outside query time (`PhysicalASAPDAGValidationError::InvalidPhysicalProperties`). Ingestion work cannot depend on a future query result. The deployment executes the plan as given and does not change its lifetime diff --git a/docs/design_docs/physical-planning-and-deployment.md b/docs/design_docs/physical-planning-and-deployment.md index 1a1299b3b..ac5b261dc 100644 --- a/docs/design_docs/physical-planning-and-deployment.md +++ b/docs/design_docs/physical-planning-and-deployment.md @@ -48,10 +48,10 @@ decided by a `PhysicalPropertiesAssignment`, as the layer contract below states. realization strategy writes while building a candidate is provisional. 2. **Materialization** (Stage 2, #509) chooses, for each sub-DAG whose output may be stored (a `SummaryAgg` or a `MaintainPopulation`), whether - it is kept and with which timing and `Lifetime` (`None`, + it is materialized and with which timing and `Lifetime` (`None`, `OneEvaluation(medium)` or `AcrossEvaluations(medium)`), and records it in a `PhysicalPropertiesAssignment`. `apply_physical_properties` writes every - node's `ExecutionTiming` and `Lifetime`: a state kept at ingestion time and + node's `ExecutionTiming` and `Lifetime`: a state materialized at ingestion time and all of its inputs run at ingestion time; readouts, other consumers, and the other states run at query time. The default assignment keeps nothing; `PlanOutput::physical_asap_dag` applies it only to nodes the optimization pass left untimed (a pass's own timing, such @@ -472,7 +472,7 @@ These derivations are methods on `PhysicalASAPDAG` in `asap-types`, so a runtime needs no dependency on the planner crate. A **materialized view** is a node whose output is kept across evaluations -(lifetime `AcrossEvaluations`, at ingestion or at query time). A node kept for +(lifetime `AcrossEvaluations`, at ingestion or at query time). A node materialized for `OneEvaluation` is not a view: its output is discarded after one evaluation. Everything a runtime needs that the DAG determines is derived from the DAG, so the plan file has no second copy to keep consistent. Stage 3's selection report is returned beside @@ -744,7 +744,7 @@ operator/runtime fixtures: | `kll_tumbling_window_execution::a_store_keyed_by_definition_and_time_range_answers_the_tumbling_windows` | A store that finds states only by `(definition_id, time range)` answers the five-tumbling-window query: the tumbling windows share one definition and request the five ranges that tile the window | | `runtime_install::tumbling_windows_of_one_refresh_window_read_each_raw_window_once` | A KLL chain and a DDSketch chain of 10 s tumbling windows over one `Scan` are one refresh group: each tumbling window window is read from raw data once, in one ingestion run that builds both tumbling windows; each state equals that of a run of its view alone, and both queries answer as the query-time reference | | `kll_tumbling_window_execution::tumbling_windows_reject_parameters_schema_and_missing_binding` | Parameter relabelling, incompatible schemas and missing views fail explicitly | -| `precompute_candidates::grouped_rate_can_be_kept_before_or_after_grouped_sum` | Stored Rate state and stored Sum state answer like query time; summing counters before Rate does not | +| `precompute_candidates::grouped_rate_can_be_materialized_before_or_after_grouped_sum` | Stored Rate state and stored Sum state answer like query time; summing counters before Rate does not | | `sql_to_physical::sql_filter_grouped_sum_executes_and_rebinds` | SQL text → candidate search → physical compilation → shared Scan predicates and grouped summary execution; NULL samples are ignored and fresh bindings produce new results | Tumbling window construction, tumbling window timestamp checks, stored identity, revisions, readiness diff --git a/docs/design_docs/proposals/planner-layering-example2-acceptance.md b/docs/design_docs/proposals/planner-layering-example2-acceptance.md index 57b6de0f3..0ec29bd09 100644 --- a/docs/design_docs/proposals/planner-layering-example2-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example2-acceptance.md @@ -49,7 +49,7 @@ workload itself. | Logical ASAP-aware optimization, Pass 1 | Each computation: exact, a specialized summary, UnivMon. 3 × 3 × 3 = **27** | Q1: exact, HLL, KMV, UnivMon (no Theta: `asap_sketchlib` has no Theta sketch). Q2, Q3: exact, UnivMon (no specialized entropy or norm summary). 4 × 2 × 2 = **16** | | Logical ASAP-aware optimization, Pass 2 | Summary-capability rule: + 1 (one UnivMon for all three, sized for ε = 0.01) + 9 (3 pairs share a UnivMon × 3 options of the third). Independent kept. **37**. Window composition left out. | Identical-expression rule (Q2 and Q3's shared per-source count, and the shared scan) and summary-capability rule (one UnivMon for two of the queries or all three, sized with each parameter's largest value among its readers): **82** | | Physical ASAP-aware optimization | Same options as Example 1: no window form → rebuilt from raw samples each refresh. | Each logical candidate with every sub-DAG `Lifetime::None`, plus `(QueryTime, OneEvaluation(Memory))` for each summary build two or more queries read: **184** | -| Plan selection | One UnivMon sized for ε = 0.01 vs three separate summaries; the shared one usually wins (one update per flow record instead of three). | 164 invalid: HLL or UnivMon for Q1 (120), whose bound has failure probability None without a distinct bound for `flows`, and UnivMon for Q2 (44), whose entropy has no guarantee. 20 valid. Under cost model 1, KMV for Q1 with the other two exact (P33) costs 6.097 per second and P1, all exact, 6.104, the exact distinct count's values held while Q1 runs; the shared per-source count costs 7.46 rebuilt for each query and 7.06 kept `OneEvaluation`; with the shared scan also built once per evaluation, KMV for Q1 (P35-m3) is selected at 5.745, and all exact costs 5.752; UnivMon for Q3 costs 8.09. | +| Plan selection | One UnivMon sized for ε = 0.01 vs three separate summaries; the shared one usually wins (one update per flow record instead of three). | 164 invalid: HLL or UnivMon for Q1 (120), whose bound has failure probability None without a distinct bound for `flows`, and UnivMon for Q2 (44), whose entropy has no guarantee. 20 valid. Under cost model 1, KMV for Q1 with the other two exact (P33) costs 6.097 per second and P1, all exact, 6.104, the exact distinct count's values held while Q1 runs; the shared per-source count costs 7.46 rebuilt for each query and 7.06 materialized `OneEvaluation`; with the shared scan also built once per evaluation, KMV for Q1 (P35-m3) is selected at 5.745, and all exact costs 5.752; UnivMon for Q3 costs 8.09. | ## Invariants and tests @@ -89,7 +89,7 @@ workload itself. Window-composition candidates are out of scope: the doc leaves them out for this example, and a summary with no window form is rebuilt at every refresh -(Example 1's table) unless a shared build is kept `OneEvaluation` within one +(Example 1's table) unless a shared build is materialized `OneEvaluation` within one evaluation. ### Plan selection @@ -113,7 +113,7 @@ it is tested only as the dominance above: one build sized for the strictest consumer costs no more than three builds that include one of that size. Whether it also beats the exact plans is the model's call. The dominance needs the shared UnivMon materialized: plan selection charges a `Lifetime::None` -node once per consuming query, so not_kept it costs three builds of the +node once per consuming query, so not_materialized it costs three builds of the strictest size. ## Ambiguities and conflicts with the planner diff --git a/docs/design_docs/proposals/planner-layering-example4-acceptance.md b/docs/design_docs/proposals/planner-layering-example4-acceptance.md index 724e1058f..a841cc225 100644 --- a/docs/design_docs/proposals/planner-layering-example4-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example4-acceptance.md @@ -66,7 +66,7 @@ between B2 (3.611) and B1 (654.54). **Reading physical properties.** The physical DAG records each node's timing and `Lifetime` (#667, #1200). Tests read them through `planner_layering_common::keeping(p, node)` without the lifetime length or -storage medium (`KeptAtIngestion`, `KeptAtQueryTime`, `NotKept`), and the kept +storage medium (`MaterializedAtIngestion`, `MaterializedAtQueryTime`, `NotMaterialized`), and the materialized event-time span through `retention_ms(p, node)`. The IR does not record retention, so the adapter derives it the way plan selection prices kept state: a chain of `N` tumbling windows of width `w` keeps `N·w`, plus one tumbling window while @@ -80,7 +80,7 @@ it. |---|---|---| | Every node upstream of an ingestion-time node also runs at ingestion time (all variants) | `stage2_physical_asap_optimization_ingestion_time_upstream_is_ingestion_time`; the monthly variant in `stage2_physical_asap_optimization_monthly_ingestion_time_upstream_is_ingestion_time` | passes: B1 and the monthly variant's maintained tumbling windows; the monthly test is ignored as slow (run in release by hand) | | With data at rest, no node runs at ingestion time | `stage2_physical_asap_optimization_at_rest_runs_nothing_at_ingestion_time` | passes | -| A materialized output covers its consumers: retention ≥ max over its readers of `lookback` + offset | `stage2_physical_asap_optimization_kept_output_covers_its_consumers`; the monthly variant in `stage2_physical_asap_optimization_monthly_kept_output_covers_its_consumers` | passes: B1 keeps 6 min ≥ 5 min; the monthly test is ignored as slow (run in release by hand) | +| A materialized output covers its consumers: retention ≥ max over its readers of `lookback` + offset | `stage2_physical_asap_optimization_materialized_output_covers_its_consumers`; the monthly variant in `stage2_physical_asap_optimization_monthly_materialized_output_covers_its_consumers` | passes: B1 keeps 6 min ≥ 5 min; the monthly test is ignored as slow (run in release by hand) | ### Pattern A @@ -88,7 +88,7 @@ it. |---|---|---| | The shared EH yields exactly A1, A2, A3 | `stage2_physical_asap_optimization_a_shared_eh_has_three_materialization_options` | ignored: the shared EH (#628, #634) | | At rest, A2 is not generated; A1 and A3 remain | `stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option` | ignored: the shared EH (#628, #634) | -| A materialized EH is one build node read by all five queries, priced once | `stage2_physical_asap_optimization_a_kept_eh_is_built_once_for_all_consumers` | ignored: the shared EH (#628, #634) | +| A materialized EH is one build node read by all five queries, priced once | `stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers` | ignored: the shared EH (#628, #634) | | A3 costs strictly more than A1 (five builds instead of one: a `Lifetime::None` node is charged per consuming query) | `stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once` | ignored: the shared EH (#628, #634) | | As given, A1 is the cheapest of the three | `stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh` | ignored: the shared EH (#628, #634) | | Monthly, A2's cost relative to A1 drops: cost(A2)/cost(A1) monthly < as given | `stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance` | ignored: the shared EH (#628, #634) | diff --git a/docs/design_docs/proposals/planner-layering.md b/docs/design_docs/proposals/planner-layering.md index 7a6dfad7c..9ef5f0513 100644 --- a/docs/design_docs/proposals/planner-layering.md +++ b/docs/design_docs/proposals/planner-layering.md @@ -567,7 +567,7 @@ The sections below describe each stage. | 0. Frontends | nothing: a query that cannot be lowered fails planning with an error | — | — | | 1, Pass 1 | what the measure or the deployment cannot compute: `RequiresExact`, `NullableAvgInput`, `NoRelationalCountSketchRealization`, `UnsupportedByDeployment`, `QuantileOutsideUnitInterval`, `TopKHeapOverOneRowPerItem`; and, only when the deployment's accuracy model and evidence cannot accept an output without its guarantee, a summary no query reading it can use: `NoErrorBoundForQueryTarget` | `PerComputationLogicalMemoCandidates::pruned_candidates`, each on its aggregate's memo group | the way to compute the measure (`HowToComputeAggregateMeasure`) | | 1, Pass 2 | nothing: it only adds candidates | — | — | -| 2 | what cannot be implemented, built or kept: `PerEntityAggregateNotExecutable` (an exact per-entity `Aggregate` the executor has no kernel for), `RawDataNotRetained` (a query-time scan of raw data the deployment does not keep), `InputHasNoBuildableProducer`, `ReachesNoQueryOutput`, `TooFewQueryReaders` (shared within one evaluation with fewer than two reading queries) | `PhysicalASAPMemoCandidates::pruned_candidates`, each on its operator node's memo group | `PhysicalCandidateKey { operator_node, properties }` | +| 2 | what cannot be implemented, built or materialized: `PerEntityAggregateNotExecutable` (an exact per-entity `Aggregate` the executor has no kernel for), `RawDataNotRetained` (a query-time scan of raw data the deployment does not keep), `InputHasNoBuildableProducer`, `ReachesNoQueryOutput`, `TooFewQueryReaders` (shared within one evaluation with fewer than two reading queries) | `PhysicalASAPMemoCandidates::pruned_candidates`, each on its operator node's memo group | `PhysicalCandidateKey { operator_node, properties }` | | 3 | valid candidates that lose, and the checks only a whole plan can make (accuracy, latency, cluster capacity) | its own `RejectionCause` | — | Stage 2's key names what a pruned candidate would have been, since kept @@ -1202,22 +1202,22 @@ The planner implements a subset of these options today. In code each option is a timing and a lifetime (`PhysicalProperties`, #1200): materialized at ingestion time is ingestion time with lifetime `AcrossEvaluations`; materialized at query time is query time with lifetime `OneEvaluation` -(reused within one evaluation) or `AcrossEvaluations` (kept for later +(reused within one evaluation) or `AcrossEvaluations` (materialized for later evaluations); not materialized is lifetime `None`. Stage 2 enumerates materialization for summary builds (`SummaryAgg` and `SummaryTumblingWindowChain`); each -is offered not kept, kept at ingestion time `AcrossEvaluations(Memory)` when -it is eligible to run at ingestion time, and kept at query time +is offered not materialized, materialized at ingestion time `AcrossEvaluations(Memory)` when +it is eligible to run at ingestion time, and materialized at query time `OneEvaluation(Memory)` when two or more queries read it. Of every other sub-DAG that two or more queries read (for example a `Scan` that a 1 m and a -5 m window both read), only the highest node is a kept-output candidate: +5 m window both read), only the highest node is a materialized-output candidate: one that a query's output, or a node only one query reads, consumes. It is -offered not kept and `OneEvaluation(Memory)` only, since raw rows are not +offered not materialized and `OneEvaluation(Memory)` only, since raw rows are not maintained at ingestion time. Below an ingestion-time build it stays not -kept: the ingestion side reads its own copy. When the deployment's +materialized: the ingestion side reads its own copy. When the deployment's capabilities declare `query_time_results_retained`, a tumbling-window chain that builds exactly one new tumbling window per evaluation is also offered query time `AcrossEvaluations(Memory)`: the tumbling windows built at query -time are kept for the next evaluations. Nothing is placed on disk yet. +time are materialized for the next evaluations. Nothing is placed on disk yet. A runtime builds every ingestion-time state on the grid of its width anchored at the epoch, so an ingestion-time build must end on that grid at every diff --git a/docs/develop_docs/asap-aware-mapping-architecture.md b/docs/develop_docs/asap-aware-mapping-architecture.md index 6133b66eb..161f93cfe 100644 --- a/docs/develop_docs/asap-aware-mapping-architecture.md +++ b/docs/develop_docs/asap-aware-mapping-architecture.md @@ -71,7 +71,7 @@ same pipeline behind the `OptimizationPass` trait. | Pass 2 memo rules: shared producers (identical expressions by memo group identity, one build at different sizes), scan-label widening, window composition (tumbling windows), rollup, exact top-k reuse and finer-aggregate reuse | `asap-logical-asap-optimization`, `pass2/memo/rules/` and `pass2/memo/window_candidates.rs`, over the helpers in `pass2/asap_aware_cse.rs` | | Enumeration of the plans a memo stands for (reference pricer, DAG viewer) | `asap-logical-asap-optimization`, `pass2/memo/enumeration.rs` | | What each summary family can merge and answer (`FamilyCapability::of`: `merge_inputs`, `readouts`) | `asap-types`, `ir/schema/family_capability.rs` | -| Stage 2: physical properties options per summary build (not kept; kept at ingestion time `AcrossEvaluations`; kept at query time `OneEvaluation` or `AcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | +| Stage 2: physical properties options per summary build (not materialized; materialized at ingestion time `AcrossEvaluations`; materialized at query time `OneEvaluation` or `AcrossEvaluations`), ingestion-time eligibility, physical operator implementation | `asap-physical-asap-optimization` | | Timing and data-state edge rules applied from a `PhysicalPropertiesAssignment` | `asap-types`, `ir/properties/timing.rs` and `ir/properties/execution_data_state.rs`; `PhysicalProperties` and `Lifetime` in `physical/properties.rs` | | Stage 3: accuracy check, latency check, resource usage (`ResourceUsage`), cost models 1–3 (`CostModel`), measured operation costs | `asap-plan-selection`, `lib.rs`; `asap-cost`, `lib.rs` and `measured.rs` | | The analytical per-operator resource model Stage 3 measures with | `asap-cost`, `analytical.rs` and `operator_statistics.rs` | @@ -99,7 +99,7 @@ The unwired maintained-population rule has been removed as well; no Stage 1 pass tumbling windows or reused, and each subset of their candidates becomes another Stage 1 candidate. 3. **Stage 2** gives each summary build its physical properties options and emits - one physical candidate per assignment (the all-not-kept one + one physical candidate per assignment (the all-not-materialized one first), skipping assignments that put a build at ingestion time over one that is not. 4. **Stage 3** checks each physical candidate: every query's root guarantee diff --git a/docs/develop_docs/asap-aware-mapping-contracts.md b/docs/develop_docs/asap-aware-mapping-contracts.md index 70f6b991b..98c9219ce 100644 --- a/docs/develop_docs/asap-aware-mapping-contracts.md +++ b/docs/develop_docs/asap-aware-mapping-contracts.md @@ -78,14 +78,14 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types ## 4. Stage 2 - Only summary builds (`SummaryAgg`, `SummaryTumblingWindowChain`) get materialization - options, each a timing and a lifetime (`PhysicalProperties`): not kept always; - kept at ingestion time, `AcrossEvaluations(Memory)`, when the build is - eligible to run as data arrives; kept at query time for `OneEvaluation(Memory)` - when two or more queries read it (reused within one evaluation); kept at + options, each a timing and a lifetime (`PhysicalProperties`): not materialized always; + materialized at ingestion time, `AcrossEvaluations(Memory)`, when the build is + eligible to run as data arrives; materialized at query time for `OneEvaluation(Memory)` + when two or more queries read it (reused within one evaluation); materialized at query time `AcrossEvaluations(Memory)` for a tumbling-window chain that builds one new tumbling window per evaluation, when the deployment declares `query_time_results_retained`. -- One `PhysicalCandidate` per assignment, the all-not-kept one first +- One `PhysicalCandidate` per assignment, the all-not-materialized one first (`P`, then `P-m`). An assignment that puts a build at ingestion time over one that is not is not generated. A logical candidate Stage 2 cannot implement becomes a `PrunedCandidate` with its reason. diff --git a/docs/develop_docs/extend-asap-aware-mapping.md b/docs/develop_docs/extend-asap-aware-mapping.md index dd6deb235..f59566dcd 100644 --- a/docs/develop_docs/extend-asap-aware-mapping.md +++ b/docs/develop_docs/extend-asap-aware-mapping.md @@ -81,7 +81,7 @@ contains the candidate and that Stage 3 prices it. `readable_at`) and its placement in `crates/types/src/ir/properties/timing.rs`, with its data-state edge rules. 2. Offer it in `crates/physical-asap-optimization/src/lib.rs` (the - `KeptOutputCandidate` options), after the existing options so default + `MaterializedOutputCandidate` options), after the existing options so default candidate ids stay the same, and gate it on the deployment input that allows it. 3. Price it in `crates/cost/src/usage.rs` (`asap_cost::node_usage`): what it keeps in memory or on diff --git a/docs/develop_docs/tumbling-window-search-compression-evaluation.md b/docs/develop_docs/tumbling-window-search-compression-evaluation.md index de049ba47..5ddcdfc26 100644 --- a/docs/develop_docs/tumbling-window-search-compression-evaluation.md +++ b/docs/develop_docs/tumbling-window-search-compression-evaluation.md @@ -110,7 +110,7 @@ The nine viewer workloads also passed **9/9**, with **40/40** query requirements ### Final regression follow-up -The regression suite found a genuine optimization regression outside window planning. Two identical SQL percentiles over an at-rest table were sent through progressive tumbling window rounds solely because they repeat every ten minutes. No computation had a tumbling-window-eligible window, so the rounds rebuilt the same 40-configuration, 150-connection model and restarted refinement. The 128-evaluation budget expired with two identical not_kept KLL builds, costing 0.007678692288679677 per second instead of the baseline's one shared query-materialized build at 0.006000017830006526 (+27.98%). The original pointer-sharing assertion failed both in the suite and in isolation; it was retained unchanged. +The regression suite found a genuine optimization regression outside window planning. Two identical SQL percentiles over an at-rest table were sent through progressive tumbling window rounds solely because they repeat every ten minutes. No computation had a tumbling-window-eligible window, so the rounds rebuilt the same 40-configuration, 150-connection model and restarted refinement. The 128-evaluation budget expired with two identical not_materialized KLL builds, costing 0.007678692288679677 per second instead of the baseline's one shared query-materialized build at 0.006000017830006526 (+27.98%). The original pointer-sharing assertion failed both in the suite and in isolation; it was retained unchanged. Revision `fe171f64` bypasses tumbling-window-domain expansion when the initial computations contain neither a positive range window nor an existing tumbling-window chain. It searches the complete candidate domain directly; at-rest status alone does not disable tumbling window planning. The same SQL fixture now passes the original sharing test and selects one shared KLL with exactly the baseline cost. Its report records 58 evaluations, `optimal`, one `Complete` round, and no pending widths. This fix avoids repeated identical-domain searches rather than increasing the budget or relaxing correctness checks. From 64e721439084a55e5aa00c4d8817ea59726b3cf9 Mon Sep 17 00:00:00 2001 From: zzylol <50204836+zzylol@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:58:48 +0000 Subject: [PATCH 9/9] refactor: finish the kept -> materialized rename; set ignores lifetime None Review fixes for #1214: the assignment's field, Debug label, set's parameter and docs, error messages, the devtools and viewer labels, the cost detail for chains across evaluations, test names, locals and the fixture name say materialized. post-asap-ir.md documents set(node, properties); the example 4 acceptance doc names materializing(). PhysicalPropertiesAssignment::set with a lifetime None removes the node's assignment in release builds too, instead of only a debug_assert. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K1M6br9PL4SDeVS1XpezKJ --- crates/cost/src/execution_demand.rs | 2 +- crates/cost/src/usage.rs | 20 ++-- crates/cost/tests/ingestion_refresh_runs.rs | 15 +-- crates/devtools/src/candidate_labels.rs | 4 +- crates/devtools/tests/asap_planner.rs | 6 +- crates/executor/src/capability.rs | 2 +- .../tests/deployment_capabilities.rs | 46 ++++++---- .../stored_outputs_on_main.json | 2 +- .../tests/physical_properties_e2e.rs | 2 +- .../tests/planner_layering_common/mod.rs | 4 +- .../tests/planner_layering_example4.rs | 16 ++-- .../tests/range_evaluation.rs | 26 ++++-- .../tests/rollup_controlled.rs | 6 +- .../tests/sharing_issue_regressions.rs | 2 +- .../src/catalog/realize.rs | 4 +- crates/physical-asap-optimization/src/lib.rs | 29 +++--- crates/plan-selection/src/lib.rs | 91 +++++++++--------- crates/planner/tests/runtime_install.rs | 12 +-- crates/types/src/ir/operator/node.rs | 2 +- crates/types/src/ir/physical_export.rs | 10 +- .../src/ir/properties/execution_data_state.rs | 6 +- crates/types/src/ir/properties/timing.rs | 92 ++++++++++++------- crates/types/src/physical/properties.rs | 10 +- crates/types/src/stages/physical/graph.rs | 2 +- crates/types/tests/physical_export.rs | 6 +- docs/design_docs/concepts/glossary.md | 2 +- docs/design_docs/concepts/post-asap-ir.md | 10 +- .../physical-planning-and-deployment.md | 2 +- .../planner-layering-example4-acceptance.md | 4 +- docs/develop_docs/pre-asap-ir.md | 2 +- tools/dag-viewer/app.js | 4 +- tools/dag-viewer/stages.js | 2 +- 32 files changed, 253 insertions(+), 190 deletions(-) diff --git a/crates/cost/src/execution_demand.rs b/crates/cost/src/execution_demand.rs index c902ef3a7..a7ddcaccf 100644 --- a/crates/cost/src/execution_demand.rs +++ b/crates/cost/src/execution_demand.rs @@ -394,7 +394,7 @@ pub fn computations( let mut rate_of_materialized = HashMap::new(); for (&id, &properties) in &materialized_nodes { let at_ingestion = properties.timing() == ExecutionTiming::IngestionTime; - // A query-time chain kept across evaluations is built once per request. + // A query-time chain materialized across evaluations is built once per request. let per_request = !at_ingestion && properties.lifetime().is_across_evaluations(); let rate = match at_ingestion { true => 1.0, diff --git a/crates/cost/src/usage.rs b/crates/cost/src/usage.rs index e4c6e98d8..781351dd1 100644 --- a/crates/cost/src/usage.rs +++ b/crates/cost/src/usage.rs @@ -1130,7 +1130,7 @@ pub fn node_usage<'a>( // latency, or a materialized consumer's longest reader's, as a // OneEvaluation state is). let state = out.bytes.max(estimate.peak_memory_bytes()); - let (kept, medium) = match (ingestion, node.lifetime, &node.payload) { + let (materialized_bytes, medium) = match (ingestion, node.lifetime, &node.payload) { (_, Lifetime::None, _) => { let working_memory_bytes = estimate.peak_memory_bytes(); peak_memory_bytes = working_memory_bytes.saturating_mul(multiplier); @@ -1139,7 +1139,7 @@ pub fn node_usage<'a>( } (0, Medium::Memory) } - // A tumbling-window chain kept across evaluations holds the tumbling windows its + // A tumbling-window chain materialized across evaluations holds the tumbling windows its // retention covers ([`tumbling_window_retention_ms`]: N, plus one per tumbling window // width of the readers' range-evaluation span), all but the // newest between evaluations and all while one runs. @@ -1169,7 +1169,7 @@ pub fn node_usage<'a>( } Medium::Disk => disk_bytes = between, } - detail += &format!("; keeps {between} bytes across evaluations"); + detail += &format!("; materializes {between} bytes across evaluations"); (0, medium) } (_, Lifetime::OneEvaluation(medium), _) => { @@ -1200,7 +1200,7 @@ pub fn node_usage<'a>( medium, ) } - // A whole state kept across evaluations: it and the one being built. + // A whole state materialized across evaluations: it and the one being built. (_, Lifetime::AcrossEvaluations(medium), _) => ( state.checked_mul(2).ok_or(AnalyticalCostError::Overflow)?, medium, @@ -1209,15 +1209,15 @@ pub fn node_usage<'a>( if ingestion && node.lifetime == Lifetime::AcrossEvaluations(Medium::Memory) { maintained = Some(state / tumbling_windows_of(node)); } - if kept > 0 { + if materialized_bytes > 0 { match medium { Medium::Memory => { - average_memory_bytes = kept as f64; - peak_memory_bytes = kept; + average_memory_bytes = materialized_bytes as f64; + peak_memory_bytes = materialized_bytes; } - Medium::Disk => disk_bytes = kept, + Medium::Disk => disk_bytes = materialized_bytes, } - detail += &format!("; keeps {kept} bytes"); + detail += &format!("; keeps {materialized_bytes} bytes"); } if let Payload::NonASAP(NonASAPOp::Scan { source, .. }) = &node.payload { if !ingestion { @@ -1599,7 +1599,7 @@ pub fn node_map(dag: &PhysicalASAPDAG) -> NodeMap<'_> { pub type NodeMap<'a> = HashMap; -/// The query-time tumbling-window chains of `dag` kept across evaluations +/// The query-time tumbling-window chains of `dag` materialized across evaluations /// (lifetime `AcrossEvaluations` at query time, which Stage 2 offers only when the /// deployment keeps query-time results and every reader builds one new /// tumbling window per evaluation). Each evaluation builds the newest tumbling window, and the diff --git a/crates/cost/tests/ingestion_refresh_runs.rs b/crates/cost/tests/ingestion_refresh_runs.rs index 7b69b7381..e41dfdcee 100644 --- a/crates/cost/tests/ingestion_refresh_runs.rs +++ b/crates/cost/tests/ingestion_refresh_runs.rs @@ -75,13 +75,16 @@ fn chain( /// One query per summary of `summaries`, merging it, with each summary /// materialized with `materialized` (`None`: not materialized): the DAG Stage 3 costs, chains /// unexpanded. -fn dag_of(summaries: &[Rc], kept: Option) -> PhysicalASAPDAG { +fn dag_of( + summaries: &[Rc], + materialized: Option, +) -> PhysicalASAPDAG { let mut assignment = PhysicalPropertiesAssignment::default(); let roots: Vec = summaries .iter() .map(|summary| { - if let Some(kept) = kept { - assignment.set(summary, kept); + if let Some(materialized) = materialized { + assignment.set(summary, materialized); } QueryRoot::Operator( OperatorNode::new_shared(Operator::ASAP(ASAPOp::SummaryMerge { @@ -133,7 +136,7 @@ fn shifted(child: &Rc, offset_ms: i64) -> Rc { } /// A KLL chain and a DDSketch chain of 10 s tumbling windows over one `Scan`, both -/// kept at ingestion, are refreshed in one ingestion run per tumbling window: the +/// materialized at ingestion, are refreshed in one ingestion run per tumbling window: the /// `Scan` is computed once per second of arriving data, not twice. #[test] fn a_scan_under_two_chains_of_one_tumbling_window_width_is_computed_once() { @@ -253,7 +256,7 @@ fn nodes_below_a_shared_intermediate_node_are_computed_once_per_run() { ); } -/// Two summaries kept at ingestion over rows with no time window +/// Two summaries materialized at ingestion over rows with no time window /// (`Values`) have no refresh window: each counts alone. #[test] fn consumers_of_unbounded_windows_count_alone() { @@ -286,7 +289,7 @@ fn consumers_of_unbounded_windows_count_alone() { ); } -/// A node whose timing and lifetime cannot go together (kept for one +/// A node whose timing and lifetime cannot go together (materialized for one /// evaluation at ingestion time) is reported, not skipped. #[test] fn an_invalid_node_is_reported_not_skipped() { diff --git a/crates/devtools/src/candidate_labels.rs b/crates/devtools/src/candidate_labels.rs index e266a0301..cf2f82035 100644 --- a/crates/devtools/src/candidate_labels.rs +++ b/crates/devtools/src/candidate_labels.rs @@ -151,7 +151,9 @@ pub fn physical_label(logical: &str, candidate: &PhysicalWorkloadPlan) -> String (_, Lifetime::None) => continue, (ExecutionTiming::IngestionTime, _) => "ingestion time", (ExecutionTiming::QueryTime, Lifetime::OneEvaluation(_)) => "query time, shared", - (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => "query time, kept", + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => { + "query time, materialized across evaluations" + } }; let label = match &node.payload { // Name the chain: chains of one family and tumbling-window count differ by diff --git a/crates/devtools/tests/asap_planner.rs b/crates/devtools/tests/asap_planner.rs index 45a6332b5..2fda7acad 100644 --- a/crates/devtools/tests/asap_planner.rs +++ b/crates/devtools/tests/asap_planner.rs @@ -1604,13 +1604,13 @@ fn scans_projecting_different_labels_are_shared() { data, false, &mut |_, readers, options| { - let kept = (readers.len() > 1) + let materialized = (readers.len() > 1) .then_some(PhysicalProperties::MATERIALIZED_IN_MEMORY_FOR_ONE_EVALUATION); - options.iter().position(|option| *option == kept) + options.iter().position(|option| *option == materialized) }, ) .unwrap() - .expect("a node read by several roots can be kept for the evaluation"); + .expect("a node read by several roots can be materialized for the evaluation"); let offered = asap_devtools::memo_pricing::reference_select( std::slice::from_ref(&physical), &entries, diff --git a/crates/executor/src/capability.rs b/crates/executor/src/capability.rs index 0885391de..d3fe75108 100644 --- a/crates/executor/src/capability.rs +++ b/crates/executor/src/capability.rs @@ -230,7 +230,7 @@ pub(crate) fn hydra_cms_shape( /// none of the query's columns for the filter predicate to read, so only a /// query-time build can apply it. The ingestion-time compiler and the /// binding of any ingestion-timed `SummaryAgg` apply this check. The planner -/// applies the same rule: Stage 2 never offers keeping at ingestion time for a +/// applies the same rule: Stage 2 never offers materializing at ingestion time for a /// filtered build (`IngestionPruneReason::Filtered`), and materialization /// timing rejects an explicit one (`FilteredSummaryAtIngestion`). This check /// guards plans that did not come from the planner. diff --git a/crates/integration-tests/tests/deployment_capabilities.rs b/crates/integration-tests/tests/deployment_capabilities.rs index 4982a8d7d..032ee5c20 100644 --- a/crates/integration-tests/tests/deployment_capabilities.rs +++ b/crates/integration-tests/tests/deployment_capabilities.rs @@ -200,10 +200,10 @@ type CandidateCosts = Vec<(String, f64)>; /// The per-second cost of every physical candidate whose tumbling-window chain both /// panels read is materialized at query time: shared within one evaluation -/// (`OneEvaluation`), and kept across evaluations +/// (`OneEvaluation`), and materialized across evaluations /// (query-time `AcrossEvaluations`, which Stage 3 prices as such). fn shared_chain_costs(run: &Run) -> (CandidateCosts, CandidateCosts) { - let (mut within_one, mut kept) = (Vec::new(), Vec::new()); + let (mut within_one, mut materialized) = (Vec::new(), Vec::new()); for p in &run.physical { for n in &p.dag().nodes { let shared_chain = matches!( @@ -214,30 +214,32 @@ fn shared_chain_costs(run: &Run) -> (CandidateCosts, CandidateCosts) { continue; }; let entry = (p.id.clone(), cost.cost_per_second.expect("cost model 1")); - let kept_detail = cost.per_node[&n.id].detail.contains("across evaluations"); + let materialized_detail = cost.per_node[&n.id].detail.contains("across evaluations"); match (n.output_state.timing, n.lifetime) { (_, Lifetime::OneEvaluation(_)) => within_one.push(entry), - (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) if kept_detail => { - kept.push(entry) + (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) + if materialized_detail => + { + materialized.push(entry) } (ExecutionTiming::QueryTime, Lifetime::AcrossEvaluations(_)) => { - panic!("{}: a kept chain priced as not kept", p.id) + panic!("{}: a materialized chain priced as not materialized", p.id) } _ => {} } } } - (within_one, kept) + (within_one, materialized) } /// With query-time results retained, a chain two panels read is offered /// both ways: shared within one evaluation (rebuilt from the 5-min window -/// every minute, then reused by both panels) and kept across evaluations +/// every minute, then reused by both panels) and materialized across evaluations /// (B3: one new tumbling window per evaluation, the 4 older tumbling windows held in memory /// between evaluations). Holding 1M per-series KLLs between evaluations /// costs far more than rebuilding them, so the shared option is cheaper -/// and the kept one is not selected. Without query-time retention, the -/// kept option is not offered. +/// and the materialized one is not selected. Without query-time retention, the +/// materialized option is not offered. #[test] fn query_time_results_retained_still_offers_the_chain_shared_within_one_evaluation() { let keeping = DeploymentCapabilities { @@ -245,9 +247,15 @@ fn query_time_results_retained_still_offers_the_chain_shared_within_one_evaluati ..DeploymentCapabilities::default() }; let run = shared_tumbling_window_configurations(&keeping); - let (within_one, kept) = shared_chain_costs(&run); - assert!(!within_one.is_empty(), "no shared option: kept {kept:?}"); - assert!(!kept.is_empty(), "no kept option: shared {within_one:?}"); + let (within_one, materialized) = shared_chain_costs(&run); + assert!( + !within_one.is_empty(), + "no shared option: materialized {materialized:?}" + ); + assert!( + !materialized.is_empty(), + "no materialized option: shared {within_one:?}" + ); let cheapest = |options: &[(String, f64)]| { options .iter() @@ -255,18 +263,20 @@ fn query_time_results_retained_still_offers_the_chain_shared_within_one_evaluati .fold(f64::INFINITY, f64::min) }; assert!( - cheapest(&within_one) < cheapest(&kept), - "shared {within_one:?}, kept {kept:?}" + cheapest(&within_one) < cheapest(&materialized), + "shared {within_one:?}, materialized {materialized:?}" ); assert!( - kept.iter().all(|(id, _)| *id != run.selection.selected), + materialized + .iter() + .all(|(id, _)| *id != run.selection.selected), "{}", run.selection.selected ); assert_selects_cheapest_valid(&run); - let (_, kept) = shared_chain_costs(&shared_tumbling_window_configurations( + let (_, materialized) = shared_chain_costs(&shared_tumbling_window_configurations( &DeploymentCapabilities::default(), )); - assert!(kept.is_empty(), "{kept:?}"); + assert!(materialized.is_empty(), "{materialized:?}"); } diff --git a/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json b/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json index ef0e50645..f822d6b70 100644 --- a/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json +++ b/crates/integration-tests/tests/materialized_view_fixtures/stored_outputs_on_main.json @@ -4,7 +4,7 @@ {"name":"repeating rollup/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":16,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":15,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":16,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":18,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":18,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":21,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":24,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":27,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":20,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":23,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":26,"role":"Input","window":"NotApplicable"},{"consumer":30,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":29,"role":"Input","window":"NotApplicable"},{"consumer":31,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":31,"role":"Input","window":"NotApplicable"},{"consumer":33,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":32,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":34,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":300000}}}}},{"guarantee":null,"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":15,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":17,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":18,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":360000}}}}},{"guarantee":null,"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":18,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":20,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":19,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":21,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":420000}}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":21,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":23,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":22,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":24,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":480000}}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":24,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":26,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":25,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":27,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":540000}}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":27,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":29,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":28,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":30,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14,17,20,23,26,29]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":30}}}},{"guarantee":null,"id":32,"lifetime":{"OneEvaluation":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":31,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":33,"lifetime":{"OneEvaluation":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":32}}}},{"guarantee":null,"id":34,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":33,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}}],"roots":[33,35],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-360000},{"included":-300000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":300000,"scan_node_id":0,"time_range_node_id":16,"width_ms":60000}],"stored_outputs":[]},"node_id":17,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-420000},{"included":-360000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":360000,"scan_node_id":0,"time_range_node_id":19,"width_ms":60000}],"stored_outputs":[]},"node_id":20,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-480000},{"included":-420000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":420000,"scan_node_id":0,"time_range_node_id":22,"width_ms":60000}],"stored_outputs":[]},"node_id":23,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-540000},{"included":-480000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":480000,"scan_node_id":0,"time_range_node_id":25,"width_ms":60000}],"stored_outputs":[]},"node_id":26,"retention_ms":600000},{"built_at":"ingestion_run","coverage":{"definition_id":"89d70c922a6f3de8ed2220ac945ac927","selection":[{"columns":[],"relative_time":[{"excluded":-600000},{"included":-540000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":540000,"scan_node_id":0,"time_range_node_id":28,"width_ms":60000}],"stored_outputs":[]},"node_id":29,"retention_ms":600000}]}, {"name":"repeating rate-5m/no_raw","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"},{"consumer":17,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":16,"role":"Input","window":"NotApplicable"},{"consumer":18,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":17,"role":"Input","window":"NotApplicable"},{"consumer":19,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":20,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":19,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":21,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":20,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":22,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":23,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":22,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":24,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":23,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":25,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":26,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":25,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":27,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":26,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":28,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":29,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":28,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":30,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":29,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":31,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":32,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":31,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":33,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":32,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":21,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":24,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":27,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":30,"role":"Input","window":"NotApplicable"},{"consumer":34,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":33,"role":"Input","window":"NotApplicable"},{"consumer":35,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":34,"role":"Input","window":"NotApplicable"},{"consumer":36,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":35,"role":"Input","window":"NotApplicable"},{"consumer":37,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"producer":36,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"latency_ms"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}},{"guarantee":null,"id":17,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":16,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":18,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":17}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":19,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3600000}}}}},{"guarantee":null,"id":20,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":19,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":21,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":20,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":22,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3660000}}}}},{"guarantee":null,"id":23,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":22,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":24,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":23,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":25,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3720000}}}}},{"guarantee":null,"id":26,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":25,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":27,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":26,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":28,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3780000}}}}},{"guarantee":null,"id":29,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":28,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":30,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":29,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":31,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":3840000}}}}},{"guarantee":null,"id":32,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":31,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":33,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":32,"family":{"ExactAggregate":["Rate","Rate"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":34,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Rate","Rate"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[21,24,27,30,33]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":35,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":34}}}},{"guarantee":null,"id":36,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":35,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":37,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":36}}}}],"roots":[18,37],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":300000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3660000},{"included":-3600000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3600000,"scan_node_id":0,"time_range_node_id":20,"width_ms":60000}],"stored_outputs":[]},"node_id":21,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3720000},{"included":-3660000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3660000,"scan_node_id":0,"time_range_node_id":23,"width_ms":60000}],"stored_outputs":[]},"node_id":24,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3780000},{"included":-3720000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3720000,"scan_node_id":0,"time_range_node_id":26,"width_ms":60000}],"stored_outputs":[]},"node_id":27,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3840000},{"included":-3780000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3780000,"scan_node_id":0,"time_range_node_id":29,"width_ms":60000}],"stored_outputs":[]},"node_id":30,"retention_ms":3900000},{"built_at":"ingestion_run","coverage":{"definition_id":"b615b22773d1e90b57e97e16aecb4b80","selection":[{"columns":[],"relative_time":[{"excluded":-3900000},{"included":-3840000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":3840000,"scan_node_id":0,"time_range_node_id":32,"width_ms":60000}],"stored_outputs":[]},"node_id":33,"retention_ms":3900000}]}, {"name":"runtime_install a_coarse_sum_rolls_up_from_the_stored_fine_sum","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":2,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":{"Named":"sum"}},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[1]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}}],"roots":[5,6],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"db0c9241a79202b6925e84aef010e89a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"3c90a6b5ff3ecaa445ea9bf285e1dc0b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, -{"name":"runtime_install a_kept_sliding_window_merge_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"NotApplicable"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"NotApplicable"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"NotApplicable"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}}],"roots":[16],"scalar_roots":[]},"stored_outputs":[{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2,5,8,11,14]},"node_id":15,"retention_ms":3900000}]}, +{"name":"runtime_install a_materialized_sliding_window_merge_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":1,"role":"Input","window":"NotApplicable"},{"consumer":3,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":3,"role":"Input","window":"NotApplicable"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":6,"role":"Input","window":"NotApplicable"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":7,"role":"Input","window":"NotApplicable"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":10,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":9,"role":"Input","window":"NotApplicable"},{"consumer":11,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":10,"role":"Input","window":"NotApplicable"},{"consumer":12,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":0,"role":"Input","window":"NotApplicable"},{"consumer":13,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":12,"role":"Input","window":"NotApplicable"},{"consumer":14,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":13,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":8,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":11,"role":"Input","window":"NotApplicable"},{"consumer":15,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":14,"role":"Input","window":"NotApplicable"},{"consumer":16,"data_state":{"primitive":"SummaryState","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"producer":15,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":null,"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":60000}}}}},{"guarantee":null,"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":3,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":120000}}}}},{"guarantee":null,"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":6,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":8,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":7,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":9,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":180000}}}}},{"guarantee":null,"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":9,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":11,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":10,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":12,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeShift":{"child":0,"shift":{"at":null,"offset_ms":240000}}}}},{"guarantee":null,"id":13,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"TimeRange":{"child":12,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":14,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryAgg":{"child":13,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":null,"id":15,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"SummaryState","timing":"query_time"},"payload":{"ASAP":{"SummaryMerge":{"children":[2,5,8,11,14]}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":16,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":15}}}}],"roots":[16],"scalar_roots":[]},"stored_outputs":[{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-120000},{"included":-60000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":60000,"scan_node_id":0,"time_range_node_id":4,"width_ms":60000}],"stored_outputs":[]},"node_id":5,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-180000},{"included":-120000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":120000,"scan_node_id":0,"time_range_node_id":7,"width_ms":60000}],"stored_outputs":[]},"node_id":8,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-240000},{"included":-180000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":180000,"scan_node_id":0,"time_range_node_id":10,"width_ms":60000}],"stored_outputs":[]},"node_id":11,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":-240000}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":240000,"scan_node_id":0,"time_range_node_id":13,"width_ms":60000}],"stored_outputs":[]},"node_id":14,"retention_ms":3900000},{"built_at":"query_run","coverage":{"definition_id":"71610a93a8af5ae7ee6ecc0839e28d3b","selection":[{"columns":[],"relative_time":[{"excluded":-300000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2,5,8,11,14]},"node_id":15,"retention_ms":3900000}]}, {"name":"runtime_install a_summary_across_series_from_per_series_summaries_is_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":4,"role":"Input","window":"NotApplicable"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":2,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"Raw","timing":"query_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":6,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":null,"id":4,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":3,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":5,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":4}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[2,0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"NonASAP":{"Project":{"child":6,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"$promql_series_identity","expr":{"Column":3}}],"qualifier":null}}}}],"roots":[5,7],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"5555de6812a18c62345c199d5ba8f06e","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"f35ee4e847802c130cbd5221a81f7ea1","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":4,"retention_ms":60000}]}, {"name":"runtime_install group_outputs_from_one_stored_per_series_sum_are_listed_and_built","dag":{"edges":[{"consumer":1,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":0,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":2,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":1,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":3,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":4,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":3,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":5,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"producer":4,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":6,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"producer":5,"role":"Input","window":"NotApplicable"},{"consumer":7,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":2,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":8,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":7,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":9,"data_state":{"primitive":"Raw","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"producer":8,"role":"Input","window":"RequiresAlignedPanePhaseOrExactBoundaryResidual"},{"consumer":10,"data_state":{"primitive":"SummaryState","timing":"ingestion_time"},"grouping":"NotApplicable","intermediate_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"producer":9,"role":"Input","window":"NotApplicable"}],"nodes":[{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":0,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Scan":{"predicates":[],"schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"source":{"TimeSeries":{"metric":"m"}}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact over exact inputs"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":1,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"TimeRange":{"child":0,"kind":"range","range":{"nanos":0,"secs":60}}}}},{"guarantee":null,"id":2,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":1,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":"PerEntity"}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":3,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":4,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[3,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":3,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":5,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Max","Max"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":4,"family":{"ExactAggregate":["Max","Max"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":6,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"max","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":5}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":7,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":2}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":8,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"timestamp"},"name":"ts","nullable":false,"table":null},{"dtype":{"Plain":"float64"},"name":"value","nullable":false,"table":null},{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"$promql_series_identity","nullable":false,"table":null}],"time_index":0,"unique_keys":[[4,0]]},"output_state":{"primitive":"Raw","timing":"ingestion_time"},"payload":{"NonASAP":{"Project":{"child":7,"cols":[{"alias":"ts","expr":{"Column":0}},{"alias":"value","expr":{"Column":1}},{"alias":"instance","expr":{"Column":3}},{"alias":"job","expr":{"Column":2}},{"alias":"$promql_series_identity","expr":{"Column":4}}],"qualifier":null}}}},{"guarantee":null,"id":9,"lifetime":{"AcrossEvaluations":"Memory"},"output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"ExactAggregate":["Sum","Sum"]},"name":"state","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"SummaryState","timing":"ingestion_time"},"payload":{"ASAP":{"SummaryAgg":{"child":8,"family":{"ExactAggregate":["Sum","Sum"]},"filter":null,"grouping":"PerSubpopulationInstance","input":{"item":null,"weight":{"Column":"SampleValue"},"weight_domain":{"kind":"unknown_or_signed"}},"reduction":{"Reduce":[2,3]}}}}},{"guarantee":{"provenance":[{"kind":"exact","reason":"exact accumulator over exact input"}],"spec":{"accuracy_metric":"absolute","accuracy_scope":"per_value","error":{"op":"zero"},"failure_probability":{"op":"zero"}}},"id":10,"lifetime":"None","output_schema":{"closed":true,"fields":[{"dtype":{"Plain":"utf8"},"name":"instance","nullable":true,"table":null},{"dtype":{"Plain":"utf8"},"name":"job","nullable":true,"table":null},{"dtype":{"Plain":"float64"},"name":"sum","nullable":false,"table":null}],"time_index":null,"unique_keys":[[0,1]]},"output_state":{"primitive":"Raw","timing":"query_time"},"payload":{"ASAP":{"FinalizeExactAccumulator":{"child":9}}}}],"roots":[6,10],"scalar_roots":[]},"stored_outputs":[{"built_at":"ingestion_run","coverage":{"definition_id":"672f965318f2bf2ba350748044719b9b","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[{"end_offset_ms":0,"scan_node_id":0,"time_range_node_id":1,"width_ms":60000}],"stored_outputs":[]},"node_id":2,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"7976839b25e74a9cfac2ab1d6d01a63a","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":5,"retention_ms":60000},{"built_at":"ingestion_run","coverage":{"definition_id":"84209f44520311bced823b9e98eaf85c","selection":[{"columns":[],"relative_time":[{"excluded":-60000},{"included":0}]}]},"inputs":{"raw_sample_windows":[],"stored_outputs":[2]},"node_id":9,"retention_ms":60000}]} ] diff --git a/crates/integration-tests/tests/physical_properties_e2e.rs b/crates/integration-tests/tests/physical_properties_e2e.rs index 07e2a27cd..0747269c4 100644 --- a/crates/integration-tests/tests/physical_properties_e2e.rs +++ b/crates/integration-tests/tests/physical_properties_e2e.rs @@ -204,7 +204,7 @@ fn values_1_to_100(schema: &SchemaRef, _metric: &str) -> Batch { } /// Materializing it at ingestion time puts the quantile's state in a materialized view; -/// Not keeping it has no view and reads the raw source at +/// Not materializing it has no view and reads the raw source at /// query time; both answer alike. #[test] fn physical_properties_decide_precompute_contents() { diff --git a/crates/integration-tests/tests/planner_layering_common/mod.rs b/crates/integration-tests/tests/planner_layering_common/mod.rs index 83ee2604b..35864cf2b 100644 --- a/crates/integration-tests/tests/planner_layering_common/mod.rs +++ b/crates/integration-tests/tests/planner_layering_common/mod.rs @@ -847,7 +847,7 @@ pub fn evaluation_interval_ms(workload: &PlanningWorkload, query: usize) -> Opti /// (`OneEvaluation` or `AcrossEvaluations`) or its storage medium. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Materializing { - /// Runs as data arrives; output kept until a query reads it. + /// Runs as data arrives; output materialized until a query reads it. MaterializedAtIngestion, /// Runs when a query first needs it; output reused by the other /// queries of the evaluation, or, as query-time `AcrossEvaluations`, @@ -857,7 +857,7 @@ pub enum Materializing { NotMaterialized, } -/// Whether physical ASAP-aware optimization keeps `node`'s output, and at +/// Whether physical ASAP-aware optimization materializes `node`'s output, and at /// which timing (#667). pub fn materializing(p: &Physical, node: NodeId) -> Materializing { let n = p.dag().nodes.iter().find(|n| n.id == node).expect("node"); diff --git a/crates/integration-tests/tests/planner_layering_example4.rs b/crates/integration-tests/tests/planner_layering_example4.rs index 0d5586463..70293e4d0 100644 --- a/crates/integration-tests/tests/planner_layering_example4.rs +++ b/crates/integration-tests/tests/planner_layering_example4.rs @@ -213,9 +213,9 @@ fn stage2_physical_asap_optimization_monthly_materialized_output_covers_its_cons // ── Pattern A ──────────────────────────────────────────────────────────── -/// The shared EH candidate yields A1 (query time, kept), A2 (ingestion time) and A3 (not materialized). +/// The shared EH candidate yields A1 (query time, materialized across evaluations), A2 (ingestion time) and A3 (not materialized). #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_shared_eh_has_three_physical_properties_options() { let found: BTreeSet<_> = eh_options(&run_promql(&once())).into_keys().collect(); assert_eq!( @@ -230,7 +230,7 @@ fn stage2_physical_asap_optimization_a_shared_eh_has_three_physical_properties_o /// With data at rest, A2 is not generated; A1 and A3 remain. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option() { let found: BTreeSet<_> = eh_options(&run_promql(&at_rest())).into_keys().collect(); assert_eq!( @@ -241,7 +241,7 @@ fn stage2_physical_asap_optimization_a_at_rest_drops_the_ingestion_time_option() /// A materialized shared EH is one build node read by all five queries, charged once. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_consumers() { let run = run_promql(&once()); for (m, (id, build)) in eh_options(&run) { @@ -271,7 +271,7 @@ fn stage2_physical_asap_optimization_a_materialized_eh_is_built_once_for_all_con /// not-materialized node once per consuming query), so it costs more than A1, /// which builds it once. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() { let run = run_promql(&once()); let options = eh_options(&run); @@ -289,7 +289,7 @@ fn stage3_plan_selection_a_rebuilding_per_query_costs_more_than_building_once() /// As given (run once, ad hoc), A1 is the cheapest of the three: A2 maintains years of history for one batch. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh() { let run = run_promql(&once()); let options = eh_options(&run); @@ -301,7 +301,7 @@ fn stage3_plan_selection_a_once_adhoc_prefers_the_query_time_eh() { /// Repeated monthly and predictable, A2's maintenance is shared by many batches, so A2 gains on A1. #[test] -#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 keeping outputs for one evaluation (OneEvaluation) is in place"] +#[ignore = "needs Pass 2 window segments shared across queries (#628, #634); Stage 2 materializing outputs for one evaluation (OneEvaluation) is in place"] fn stage3_plan_selection_a_monthly_amortizes_ingestion_time_maintenance() { let ratio = |workload: PlanningWorkload| { let run = run_promql(&workload); @@ -324,7 +324,7 @@ fn keeping_query_time_results() -> DeploymentCapabilities { } } -/// The 1-min tumbling KLL candidate yields B1 (ingestion time), B2 (not materialized) and B3 (query time, kept). +/// The 1-min tumbling KLL candidate yields B1 (ingestion time), B2 (not materialized) and B3 (query time, materialized across evaluations). #[test] fn stage2_physical_asap_optimization_b_tumbling_kll_has_three_physical_properties_options() { let run = run_pattern_b_fixture( diff --git a/crates/integration-tests/tests/range_evaluation.rs b/crates/integration-tests/tests/range_evaluation.rs index 897d2921d..ad173f8cd 100644 --- a/crates/integration-tests/tests/range_evaluation.rs +++ b/crates/integration-tests/tests/range_evaluation.rs @@ -217,20 +217,30 @@ fn stage3_plan_selection_prices_61_evaluations_per_dashboard_request() { for id in ["P1", "P2", "P3"] { assert!(close(cost(&range, id), 61.0 * cost(&none, id)), "{id}"); } - // B3: 4 → 64 tumbling windows kept between requests; B1: 6 → 66 tumbling windows kept. - let keeps = |run: &Run, id: &str, bytes: &str| { + // B3: 4 → 64 tumbling windows materialized between requests; B1: 6 → 66. + let materializes = |run: &Run, id: &str, detail: &str| { assert!( run.selection.costs[id] .per_node .values() - .any(|n| n.detail.contains(&format!("; keeps {bytes} bytes"))), - "{id} keeps {bytes} bytes" + .any(|n| n.detail.contains(detail)), + "{id}: {detail}" ) }; - keeps(&none, "P3-m2", "3488000000"); - keeps(&range, "P3-m2", "55808000000"); - keeps(&none, "P3-m1", "5232000000"); - keeps(&range, "P3-m1", "57552000000"); + // B3, a query-time chain materialized across evaluations. + materializes( + &none, + "P3-m2", + "; materializes 3488000000 bytes across evaluations", + ); + materializes( + &range, + "P3-m2", + "; materializes 55808000000 bytes across evaluations", + ); + // B1, an ingestion-time state. + materializes(&none, "P3-m1", "; keeps 5232000000 bytes"); + materializes(&range, "P3-m1", "; keeps 57552000000 bytes"); assert_eq!(range.selection.selected, "P2"); } diff --git a/crates/integration-tests/tests/rollup_controlled.rs b/crates/integration-tests/tests/rollup_controlled.rs index 75146cc1f..a07c83f6e 100644 --- a/crates/integration-tests/tests/rollup_controlled.rs +++ b/crates/integration-tests/tests/rollup_controlled.rs @@ -116,10 +116,10 @@ fn controlled_distinct_rollup_prices_the_original_workload() { data, models.deployment_capabilities.query_time_results_retained, &mut |node, _, options| { - // Kept for one evaluation where offered, as two + // Materialized for one evaluation where offered, as two // queries reading one build allow. - let shared = options.iter().position(|kept| { - kept.is_some_and(|p| { + let shared = options.iter().position(|materialized| { + materialized.is_some_and(|p| { matches!( p.lifetime(), asap_types::physical::Lifetime::OneEvaluation(_) diff --git a/crates/integration-tests/tests/sharing_issue_regressions.rs b/crates/integration-tests/tests/sharing_issue_regressions.rs index 09fa114ec..7586e8f23 100644 --- a/crates/integration-tests/tests/sharing_issue_regressions.rs +++ b/crates/integration-tests/tests/sharing_issue_regressions.rs @@ -58,7 +58,7 @@ fn cost(w: &FuzzWorkload) -> f64 { } /// #923: deriving the coarse sum costs only a sum over the 150 fine groups. -/// Stage 2 offers that plan; Stage 3 keeps a `OneEvaluation` build whose +/// Stage 2 offers that plan; Stage 3 selects a `OneEvaluation` build whose /// not-materialized sibling would avoid a second scan (#1142). #[test] #[ignore = "Stage 3 misses the cheaper plan Stage 2 offers (#1142)"] diff --git a/crates/physical-asap-optimization/src/catalog/realize.rs b/crates/physical-asap-optimization/src/catalog/realize.rs index f9fa7862e..eeca63db6 100644 --- a/crates/physical-asap-optimization/src/catalog/realize.rs +++ b/crates/physical-asap-optimization/src/catalog/realize.rs @@ -66,10 +66,10 @@ pub fn realize_selected_candidates( seen[node] = true; assignments[node] }); - // The option keeping it as requested; option `None` (not materialized) + // The option materializing it as requested; option `None` (not materialized) // for a requested lifetime `None`, at either timing. let chosen = options.iter().position(|option| match option { - Some(kept) => *kept == requested, + Some(materialized) => *materialized == requested, None => !requested.lifetime().is_materialized(), }); if chosen.is_none() { diff --git a/crates/physical-asap-optimization/src/lib.rs b/crates/physical-asap-optimization/src/lib.rs index b0ffc7c12..c5008008b 100644 --- a/crates/physical-asap-optimization/src/lib.rs +++ b/crates/physical-asap-optimization/src/lib.rs @@ -223,9 +223,9 @@ pub(crate) struct SummaryMaterializationEligibility { pub(crate) enum SummaryEligibilityError { #[error("selected reader {query} has no workload entry")] UnknownReader { query: usize }, - #[error("keep eligibility requires a summary build or tumbling-window chain")] + #[error("materialization eligibility requires a summary build or tumbling-window chain")] NotSummary, - #[error("keep eligibility requires at least one selected reader")] + #[error("materialization eligibility requires at least one selected reader")] NoSelectedReaders, #[error("tumbling-window width must be positive")] ZeroPaneWidth, @@ -351,7 +351,7 @@ pub(crate) struct MaterializedOutputCandidate { impl MaterializedOutputCandidate { /// Its options, not materialized first: materialized at ingestion time when eligible, /// `OneEvaluation` when two or more queries read it, and - /// query-time `AcrossEvaluations` when it may be kept across + /// query-time `AcrossEvaluations` when it may be materialized across /// evaluations. pub(crate) fn options(&self) -> Vec> { let mut options = vec![None]; @@ -462,7 +462,7 @@ pub(crate) type ChoosePhysicalProperties<'a> = /// the address of the logical node of `roots` it implements (null when it /// implements none, e.g. a node the implementation adds) and `readers` the /// queries that read it. `None` when `choose` rejects, a chosen index is -/// out of range, or the assignment keeps a build at ingestion time +/// out of range, or the assignment materializes a build at ingestion time /// above one at query time. The search that decodes one plan from a model /// solution uses it to build that plan alone, not every assignment. pub(crate) fn optimize_physical_asap_chosen( @@ -522,11 +522,11 @@ fn assigned_candidate( assignment: Vec>, ) -> Result { let mut options = PhysicalPropertiesAssignment::default(); - for (materialized_output_candidate, kept) in + for (materialized_output_candidate, materialized) in materialized_output_candidates.iter().zip(&assignment) { - if let Some(kept) = *kept { - options.set(&materialized_output_candidate.node, kept); + if let Some(materialized) = *materialized { + options.set(&materialized_output_candidate.node, materialized); } } let operators: Vec> = implemented @@ -936,8 +936,8 @@ fn down_closed( below: &[Vec], assignment: &[Option], ) -> bool { - let at_ingestion = |kept: &Option| { - kept.is_some_and(|p| p.timing() == ExecutionTiming::IngestionTime) + let at_ingestion = |materialized: &Option| { + materialized.is_some_and(|p| p.timing() == ExecutionTiming::IngestionTime) }; assignment.iter().enumerate().all(|(c, m)| { !at_ingestion(m) @@ -1566,7 +1566,7 @@ mod tests { } /// The lifetimes `candidate` chose other than `None`, by node. - fn kept(candidate: &PhysicalWorkloadPlan) -> Vec { + fn materialized(candidate: &PhysicalWorkloadPlan) -> Vec { candidate .dag .nodes @@ -1774,7 +1774,10 @@ mod tests { .nodes .iter() .all(|n| n.output_state.timing == ExecutionTiming::QueryTime)); - assert_eq!(kept(b1), [Lifetime::AcrossEvaluations(Medium::Memory)]); + assert_eq!( + materialized(b1), + [Lifetime::AcrossEvaluations(Medium::Memory)] + ); let [chain] = &node_of(b1, "SummaryTumblingWindowChain")[..] else { panic!("one chain") }; @@ -2095,7 +2098,7 @@ mod tests { ) .unwrap(); assert_eq!( - kept(&candidates[1]), + materialized(&candidates[1]), [Lifetime::AcrossEvaluations(Medium::Memory)] ); @@ -2251,7 +2254,7 @@ mod tests { optimize_physical_asap("L1", &roots, &[], &DataWorkload::default(), false).unwrap(); assert_eq!(candidates.len(), 2); assert_eq!( - kept(&candidates[1]), + materialized(&candidates[1]), [Lifetime::OneEvaluation(Medium::Memory)] ); let [build] = &node_of(&candidates[1], "SummaryAgg")[..] else { diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index 66e4c143d..394fc8946 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -2424,10 +2424,10 @@ mod tests { } /// `candidates` with every state node (a summary build or an exact - /// aggregate) kept across evaluations, so selection charges its materialized - /// bytes every second (a state kept for one evaluation is held only for + /// aggregate) materialized across evaluations, so selection charges its materialized + /// bytes every second (a state materialized for one evaluation is held only for /// that evaluation). - fn keeping_state(mut candidates: Vec) -> Vec { + fn materializing_state(mut candidates: Vec) -> Vec { for candidate in &mut candidates { for node in &mut candidate.dag.nodes { if matches!( @@ -2459,7 +2459,7 @@ mod tests { ("quantile by (job) (0.99, rate(x[5m]))", false), ] { let checked = target.clone().accuracy_metric(AccuracyMetric::Rank); - let candidates = keeping_state(all_candidates_sized(query, &target, &|roots| { + let candidates = materializing_state(all_candidates_sized(query, &target, &|roots| { sized_as_pass1(&roots, std::slice::from_ref(&checked), &data) })); let selection = select_among_plans( @@ -2472,7 +2472,7 @@ mod tests { SelectionModels::builtin(), ) .unwrap(); - let kept_bytes = |sketch: bool| { + let materialized_bytes = |sketch: bool| { let candidate = candidates .iter() .find(|c| { @@ -2488,11 +2488,17 @@ mod tests { match large_groups { true => { assert!(has_summary_estimate(selected), "{query}: {selection:?}"); - assert!(kept_bytes(true) < kept_bytes(false), "{query}"); + assert!( + materialized_bytes(true) < materialized_bytes(false), + "{query}" + ); } false => { assert!(!has_summary_estimate(selected), "{query}: {selection:?}"); - assert!(kept_bytes(true) >= kept_bytes(false), "{query}"); + assert!( + materialized_bytes(true) >= materialized_bytes(false), + "{query}" + ); } } } @@ -2537,7 +2543,8 @@ mod tests { let target = AccuracyTarget::max_error(0.01).failure_probability(0.01); let one_series = with_series(Some(1)); for (data, sketch_wins) in [(data(), false), (one_series, true)] { - let candidates = keeping_state(all_candidates("distinct_over_time(x[5m])", &target)); + let candidates = + materializing_state(all_candidates("distinct_over_time(x[5m])", &target)); let selection = select_among_plans( &candidates, &[entry_with( @@ -3421,7 +3428,7 @@ mod tests { /// `quantile_over_time(0.99, m[1m])` with its KLL candidate chosen, its /// state materialized with `materialized` (`None`: not materialized). - fn kll_dag(kept: Option) -> PhysicalASAPDAG { + fn kll_dag(materialized: Option) -> PhysicalASAPDAG { use asap_types::ir::{ apply_physical_properties, NodeToTimedNodeCache, PhysicalPropertiesAssignment, }; @@ -3462,8 +3469,8 @@ mod tests { .find(|n| matches!(n.asap(), Some(ASAPOp::SummaryAgg { .. }))) .expect("a KLL state"); let mut assignment = PhysicalPropertiesAssignment::default(); - if let Some(kept) = kept { - assignment.set(&state, kept); + if let Some(materialized) = materialized { + assignment.set(&state, materialized); } let timed = apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache::new()).unwrap(); @@ -3597,13 +3604,13 @@ mod tests { /// and dropped within a query (not materialized) is held while that /// query runs too, and charged the same way. #[test] - fn kept_state_is_charged_per_byte_per_second() { + fn materialized_state_is_charged_per_byte_per_second() { let cost = |dag: &PhysicalASAPDAG, w| { let settings = unit_costs(|c| c.cost_per_memory_byte_second = w); price(dag, &recurrences(1), &data(), &settings).unwrap() }; - for kept in [AT_INGESTION, AT_QUERY, None] { - let dag = kll_dag(kept); + for materialized in [AT_INGESTION, AT_QUERY, None] { + let dag = kll_dag(materialized); let build = node_of(&dag, is_build); let (with, without) = (cost(&dag, 1.25e-7), cost(&dag, 0.0)); let Payload::ASAP(ASAPOp::SummaryAgg { family, .. }) = @@ -3615,7 +3622,7 @@ mod tests { // each sees its series' 12 samples: the 120 000 rows of its // source's 1-min window (data()'s 10 000 rows per second over its // five sources); at ingestion time its samples are unknown. - let samples = if kept == AT_INGESTION { + let samples = if materialized == AT_INGESTION { StateInputRows::UNKNOWN } else { StateInputRows { @@ -3624,7 +3631,7 @@ mod tests { } }; let state = 10_000.0 * summary_shape(family, samples).1 as f64; - let byte_seconds = if kept == AT_INGESTION { + let byte_seconds = if materialized == AT_INGESTION { 2.0 * state } else { let evaluation_s = with.usage.latency_per_query[0].total_ms() / 1_000.0; @@ -3637,7 +3644,7 @@ mod tests { - without.per_node[&build].cost_per_second.unwrap(); assert!( close(term, 1.25e-7 * byte_seconds), - "{kept:?}: {term} vs {}", + "{materialized:?}: {term} vs {}", 1.25e-7 * byte_seconds ); // The candidate's memory term covers every node's held memory, @@ -3683,8 +3690,8 @@ mod tests { (query.to_string(), dag) }) .collect(); - for kept in [AT_INGESTION, AT_QUERY, None] { - dags.push((format!("{kept:?}"), kll_dag(kept))); + for materialized in [AT_INGESTION, AT_QUERY, None] { + dags.push((format!("{materialized:?}"), kll_dag(materialized))); } for (name, dag) in &dags { let (term, usage) = memory_term(dag); @@ -3708,8 +3715,8 @@ mod tests { /// keeps: a materialized exact quantile keeps every value of its group, /// a sum one value per group. #[test] - fn kept_exact_state_is_charged_by_the_values_it_keeps() { - let kept = |query: &str| { + fn materialized_exact_state_is_charged_by_the_values_it_holds() { + let materialized_bytes = |query: &str| { let root = lower_promql(query, AccuracyTarget::exact()); let mut dag = optimize_physical_asap("L", &[QueryRoot::Operator(root)], &[], &data(), false) @@ -3738,8 +3745,8 @@ mod tests { (cost(1.0) - cost(0.0)).round() as u64 }; let (quantile, sum) = ( - kept("quantile by (job) (0.99, m)"), - kept("sum by (job) (m)"), + materialized_bytes("quantile by (job) (0.99, m)"), + materialized_bytes("sum by (job) (m)"), ); assert!(quantile > 10 * sum, "{quantile} vs {sum}"); } @@ -4071,15 +4078,15 @@ mod tests { assert_eq!(*b3, with_chain(Lifetime::AcrossEvaluations(Medium::Memory))); let recurrence = [repeating(MINUTE)]; let settings = CostInputs::default(); - let kept = price(b3, &recurrence, &arriving(10_000.0), &settings).unwrap(); + let materialized = price(b3, &recurrence, &arriving(10_000.0), &settings).unwrap(); let rebuilt = price(b2, &recurrence, &arriving(10_000.0), &settings).unwrap(); let scan = node_of(b3, is_scan); - assert_eq!(scanned_samples(&kept, scan), 10_000 * 60); + assert_eq!(scanned_samples(&materialized, scan), 10_000 * 60); assert_eq!( scanned_samples(&rebuilt, node_of(b2, is_scan)), 10_000 * 300 ); - assert_eq!(kept.usage.disk_bytes * 5, rebuilt.usage.disk_bytes); + assert_eq!(materialized.usage.disk_bytes * 5, rebuilt.usage.disk_bytes); let Payload::ASAP(ASAPOp::SummaryTumblingWindowChain { family, .. }) = &b3.nodes.iter().find(|n| n.id == chain).unwrap().payload else { @@ -4092,29 +4099,29 @@ mod tests { non_negative: false, }; let (_, state_bytes) = summary_shape(family, samples); - let chain_cost = &kept.per_node[&chain]; + let chain_cost = &materialized.per_node[&chain]; assert!(chain_cost.detail.contains("; x 0.0167/s"), "{chain_cost:?}"); // One state per series: arriving() declares 10 000. let between = 4 * 10_000 * state_bytes; assert!(chain_cost .detail - .contains(&format!("keeps {between} bytes across evaluations"))); - // On disk, the same N − 1 older tumbling windows are kept. + .contains(&format!("materializes {between} bytes across evaluations"))); + // On disk, the same N − 1 older tumbling windows are materialized. let on_disk = with_chain(Lifetime::AcrossEvaluations(Medium::Disk)); let on_disk = price(&on_disk, &recurrence, &arriving(10_000.0), &settings).unwrap(); assert_eq!( on_disk.usage.disk_bytes, - kept.usage.disk_bytes + between, + materialized.usage.disk_bytes + between, "{on_disk:?}" ); - // Shared within one evaluation, nothing is kept between them. + // Shared within one evaluation, nothing is materialized between them. let shared = with_chain(Lifetime::OneEvaluation(Medium::Memory)); let within_one = price(&shared, &recurrence, &arriving(10_000.0), &settings).unwrap(); assert_eq!(scanned_samples(&within_one, scan), 10_000 * 300); assert!(!within_one.per_node[&chain] .detail .contains("across evaluations")); - assert!(within_one.usage.average_memory_bytes < kept.usage.average_memory_bytes); + assert!(within_one.usage.average_memory_bytes < materialized.usage.average_memory_bytes); } fn is_chain(payload: &Payload) -> bool { @@ -4171,15 +4178,17 @@ mod tests { ) .unwrap() .per_node[&chain]; - let kept = 6 * 10_000 * state_bytes; + let materialized_bytes = 6 * 10_000 * state_bytes; assert!( close( with_memory.cost_per_second.unwrap() - work.cost_per_second.unwrap(), - 1.25e-7 * kept as f64 + 1.25e-7 * materialized_bytes as f64 ), "{with_memory:?}" ); - assert!(with_memory.detail.contains(&format!("keeps {kept} bytes"))); + assert!(with_memory + .detail + .contains(&format!("keeps {materialized_bytes} bytes"))); } /// The latency check (S6, sketch-bench cost model §5): a query's @@ -5009,24 +5018,24 @@ mod tests { let workers = cost.usage.peak_cpu_cores - 1; assert!(workers > 1, "{workers}"); // The chain keeps 6 tumbling windows (5 read and the one being built). - let kept: u64 = detail + let materialized_bytes: u64 = detail .split("; keeps ") .nth(1) .and_then(|rest| rest.split(' ').next()) .and_then(|bytes| bytes.parse().ok()) .unwrap_or_else(|| panic!("{detail}")); let copies = workers - 1; - let bytes = u64::from(copies) * (kept / 6); + let bytes = u64::from(copies) * (materialized_bytes / 6); assert!( detail.contains(&format!( "; {copies} partial copies of its newest window, {bytes} bytes" )), "{detail}" ); - // At the peak, not on average: the kept bytes are B1's only + // At the peak, not on average: the materialized bytes are B1's only // averaged memory beside negligible query-time holds. - assert!(cost.usage.peak_memory_bytes >= kept + bytes); - assert!(cost.usage.average_memory_bytes < (kept + bytes) as f64); + assert!(cost.usage.peak_memory_bytes >= materialized_bytes + bytes); + assert!(cost.usage.average_memory_bytes < (materialized_bytes + bytes) as f64); } /// The KLL build of a `quantile_over_time` candidate, with its sketch @@ -5629,7 +5638,7 @@ mod tests { /// A measured `memory_bytes_per_state` sizes the state a build keeps, /// in place of the bytes the formulas derive from its parameters. #[test] - fn measured_state_bytes_size_the_kept_state() { + fn measured_state_bytes_size_the_materialized_state() { let candidates = tumbling_window_candidates(10_000.0); let maintained = &candidates[1]; let kll = maintained diff --git a/crates/planner/tests/runtime_install.rs b/crates/planner/tests/runtime_install.rs index bdf428cf3..e14defe00 100644 --- a/crates/planner/tests/runtime_install.rs +++ b/crates/planner/tests/runtime_install.rs @@ -1579,8 +1579,8 @@ fn untime( ) if node.lifetime.is_materialized() => node.physical_properties().map(Result::unwrap), _ => None, }; - if let Some(kept) = store(node).or(own) { - assignment.set(©, kept); + if let Some(materialized) = store(node).or(own) { + assignment.set(©, materialized); } untimed.insert(Rc::as_ptr(node), Rc::clone(©)); copy @@ -1592,8 +1592,8 @@ fn summaries_at_ingestion(node: &OperatorNode) -> Option { .then(|| PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION) } -/// Every `SummaryMerge` built at query time and kept across evaluations. -fn merges_kept(node: &OperatorNode) -> Option { +/// Every `SummaryMerge` built at query time and materialized across evaluations. +fn merges_materialized(node: &OperatorNode) -> Option { matches!(node.asap(), Some(ASAPOp::SummaryMerge { .. })) .then(|| PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_QUERY_TIME) } @@ -1825,7 +1825,7 @@ async fn a_summary_across_series_from_per_series_summaries_is_listed_and_built() /// from the stored tumbling windows it answers as the reference, and a minute later /// only the newest tumbling window and the new merge are refreshed. #[tokio::test] -async fn a_kept_sliding_window_merge_is_listed_and_built() { +async fn a_materialized_sliding_window_merge_is_listed_and_built() { let capabilities = DeploymentCapabilities { query_time_results_retained: true, ..DeploymentCapabilities::default() @@ -1843,7 +1843,7 @@ async fn a_kept_sliding_window_merge_is_listed_and_built() { .and_then(|data| data.sources.get_mut("m")) .unwrap(); facts.sample_interval = Some(asap_types::workload::DurationMs(1_000)); - let plan_json = forced_plan_json(&workload, &capabilities, merges_kept).await; + let plan_json = forced_plan_json(&workload, &capabilities, merges_materialized).await; let plan: InstallablePlan = serde_json::from_str(&plan_json).unwrap(); let views = plan.materialized_views().unwrap(); let (merge, tumbling_windows) = views.split_last().unwrap(); diff --git a/crates/types/src/ir/operator/node.rs b/crates/types/src/ir/operator/node.rs index c6c5594be..713a7fcba 100644 --- a/crates/types/src/ir/operator/node.rs +++ b/crates/types/src/ir/operator/node.rs @@ -93,7 +93,7 @@ impl Operator { /// at construction and retained. `guarantee` is `None` until accuracy /// assessment establishes one (`None` never means exact). `timing` is `None` /// until a physical properties assignment is applied; export rejects an executable -/// node without one. `lifetime` is how long that assignment keeps this +/// node without one. `lifetime` is how long that assignment materializes this /// node's output (`None` until then, and for every node whose output is not /// materialized); with `timing` it is the node's [`crate::physical::PhysicalProperties`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/crates/types/src/ir/physical_export.rs b/crates/types/src/ir/physical_export.rs index dd62b88a3..5d0d7acd5 100644 --- a/crates/types/src/ir/physical_export.rs +++ b/crates/types/src/ir/physical_export.rs @@ -71,7 +71,7 @@ pub struct PhysicalASAPDAGNode { pub payload: PhysicalASAPOperatorPayload, /// Phase is a placement choice for every operator, independent of payload kind. pub output_state: ExecutionDataState, - /// How long and where the deployment keeps this node's output: the + /// How long and where the deployment materializes this node's output: the /// lifetime the physical properties assignment chose for the sub-DAG this /// node produces. Any node may be materialized (#509 §Materialization); a node /// with no assignment has lifetime `None`. With `output_state.timing` it @@ -79,7 +79,7 @@ pub struct PhysicalASAPDAGNode { pub lifetime: Lifetime, pub output_schema: Schema, pub guarantee: Option, - /// For a materialized view (a node whose lifetime keeps its output + /// For a materialized view (a node whose lifetime materializes its output /// across evaluations), how far back from the newest evaluation /// time its output must stay available once refreshed; for a query-time /// `Scan`, how far back its source's rows must stay available (`None` @@ -189,7 +189,9 @@ pub enum PhysicalASAPDAGValidationError { }, /// A summary build (or maintained population) that is not materialized but does /// not run at query time: a planner bug. - #[error("node {node:?} is a summary build that is not kept but does not run at query time")] + #[error( + "node {node:?} is a summary build that is not materialized but does not run at query time" + )] UnmaterializedSummaryBuildNotAtQueryTime { node: PhysicalASAPNodeId }, #[error("ingestion node {consumer:?} depends on query node {producer:?}")] QueryDependencyInIngestion { @@ -423,7 +425,7 @@ impl PhysicalASAPDAG { /// - a `TimeRange(w)`, range or instant: `(T - s - w, T - s]`; /// - a `SummaryTumblingWindowChain` of `n` tumbling windows of width `w`: its whole window `(T - s - /// n·w, T - s]`, or only its newest tumbling window `(T - s - w, T - s]` for a - /// chain in `materialized_chains` (kept across evaluations, so each + /// chain in `materialized_chains` (materialized across evaluations, so each /// evaluation builds one tumbling window). /// /// `Unbounded` when a root, any other reader, or a shift with an `@` diff --git a/crates/types/src/ir/properties/execution_data_state.rs b/crates/types/src/ir/properties/execution_data_state.rs index e132d0109..ac336479c 100644 --- a/crates/types/src/ir/properties/execution_data_state.rs +++ b/crates/types/src/ir/properties/execution_data_state.rs @@ -104,7 +104,7 @@ pub enum ExecutionDataStateError { /// Bad input (a hand-built or candidate-fixed plan), not an internal bug. #[error( "a query-time {edge} reads {operator} output produced at ingestion time that is not \ - stored (not kept at ingestion time)" + stored (not materialized at ingestion time)" )] UnstoredIngestionInputUnderQueryTimeSummary { edge: &'static str, @@ -138,7 +138,7 @@ pub enum ExecutionDataStateError { /// root assigned materialized at ingestion time is valid; the query reads the stored /// output. #[error( - "{operator} root runs at ingestion time but is not kept there: no query reads its \ + "{operator} root runs at ingestion time but is not materialized there: no query reads its \ output" )] UnstoredIngestionRoot { operator: &'static str }, @@ -146,7 +146,7 @@ pub enum ExecutionDataStateError { /// fixed (e.g. a query-time `FinalizeExactAccumulator` read boundary) /// that needs the other timing. #[error( - "{operator} is fixed at {} by its candidate; its assigned kept output {assigned:?} needs \ + "{operator} is fixed at {} by its candidate; its assigned materialized output {assigned:?} needs \ the other timing", fixed.as_str() )] diff --git a/crates/types/src/ir/properties/timing.rs b/crates/types/src/ir/properties/timing.rs index 9d9a31168..f934ea019 100644 --- a/crates/types/src/ir/properties/timing.rs +++ b/crates/types/src/ir/properties/timing.rs @@ -27,7 +27,7 @@ //! //! A node whose timing a candidate builder fixed (e.g. the query-time //! `FinalizeExactAccumulator` of `finalize_query_candidate`) keeps that -//! timing. An explicit assignment on it that agrees is kept; one that needs +//! timing. An explicit assignment on it that agrees is used; one that needs //! the other timing is an error //! ([`ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming`]). //! A root may be materialized at ingestion time across evaluations: the query reads @@ -75,44 +75,50 @@ use crate::physical::{Lifetime, PhysicalProperties}; /// output is materialized (by identity); any node may be assigned. A node without /// an assignment is not materialized: a summary build or `MaintainPopulation` then /// runs at query time, every other node when its consumer runs. `Default` -/// keeps nothing. +/// materializes nothing. /// /// The assignment keeps every assigned node alive, so a later allocation /// cannot reuse its address and match a stale entry. #[derive(Clone, Default)] pub struct PhysicalPropertiesAssignment { - kept: HashMap<*const OperatorNode, (Rc, PhysicalProperties)>, + materialized: HashMap<*const OperatorNode, (Rc, PhysicalProperties)>, } /// Each materialized node as its operator kind and address, not its whole sub-DAG. impl std::fmt::Debug for PhysicalPropertiesAssignment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let kept: Vec<_> = self - .kept + let materialized: Vec<_> = self + .materialized .iter() .map(|(ptr, (node, properties))| { (format!("{}@{ptr:p}", node.operator.kind_name()), properties) }) .collect(); f.debug_struct("PhysicalPropertiesAssignment") - .field("kept", &kept) + .field("materialized", &materialized) .finish() } } impl PhysicalPropertiesAssignment { - /// Keep the output of the sub-DAG `node` produces with `materialized`'s timing - /// and lifetime. `materialized` must keep the output (lifetime not `None`). - pub fn set(&mut self, node: &Rc, kept: PhysicalProperties) { - debug_assert!(kept.lifetime().is_materialized(), "{kept:?} does not keep"); - self.kept.insert(Rc::as_ptr(node), (Rc::clone(node), kept)); + /// Materialize the output of the sub-DAG `node` produces with `materialized`'s + /// timing and lifetime. A `materialized` whose lifetime is `None` does not + /// materialize the output: it removes any assignment of `node`, so `node` + /// is not materialized, in debug and release builds alike. + pub fn set(&mut self, node: &Rc, materialized: PhysicalProperties) { + if materialized.lifetime().is_materialized() { + self.materialized + .insert(Rc::as_ptr(node), (Rc::clone(node), materialized)); + } else { + self.materialized.remove(&Rc::as_ptr(node)); + } } /// Give `copy` the assignment of `original`, if it has one: for a node /// rebuilt as a copy of another. pub fn copy_assignment(&mut self, original: &OperatorNode, copy: &Rc) { - if let Some(kept) = self.get(original) { - self.set(copy, kept); + if let Some(materialized) = self.get(original) { + self.set(copy, materialized); } } @@ -156,9 +162,9 @@ impl PhysicalPropertiesAssignment { /// How `node` is materialized, if it is. fn get(&self, node: &OperatorNode) -> Option { - self.kept + self.materialized .get(&(node as *const OperatorNode)) - .map(|(_, kept)| *kept) + .map(|(_, materialized)| *materialized) } /// How `node` is materialized, checked against what is below it: @@ -170,21 +176,23 @@ impl PhysicalPropertiesAssignment { upstream_at_query_time: bool, ) -> Result, ExecutionDataStateError> { match self.get(node) { - Some(kept) - if kept.timing() == ExecutionTiming::IngestionTime && is_filtered_build(node) => + Some(materialized) + if materialized.timing() == ExecutionTiming::IngestionTime + && is_filtered_build(node) => { Err(ExecutionDataStateError::FilteredSummaryAtIngestion { operator: node.operator.kind_name(), }) } - Some(kept) - if kept.timing() == ExecutionTiming::IngestionTime && upstream_at_query_time => + Some(materialized) + if materialized.timing() == ExecutionTiming::IngestionTime + && upstream_at_query_time => { Err(ExecutionDataStateError::UpstreamNotAtIngestion { operator: node.operator.kind_name(), }) } - kept => Ok(kept), + materialized => Ok(materialized), } } } @@ -305,7 +313,7 @@ fn forces_query_time( match assignment.resolve(node, upstream) { Ok(None) if !is_materializable_state_output(&node.operator) => upstream, Ok(None) => true, - Ok(Some(kept)) => kept.timing() == ExecutionTiming::QueryTime, + Ok(Some(materialized)) => materialized.timing() == ExecutionTiming::QueryTime, Err(_) => true, } } @@ -390,7 +398,7 @@ pub fn apply_physical_properties_to_roots( /// `root` consumed at `root_timing`. For planning-time legality checks of a /// candidate before it is assembled into a workload DAG: a candidate must stay /// executable if materialization later puts its states at ingestion time. -/// Nothing is kept. +/// Nothing is materialized. #[cfg(any(test, feature = "test-support"))] pub fn validate_at_ingestion( root: &Rc, @@ -419,7 +427,7 @@ pub fn planned_data_state( std::slice::from_ref(node), ); let (timing, _) = placement(node, consumer, &assignment, &mut forced) - .expect("an assignment kept where allowed never fails"); + .expect("an assignment materialized where allowed never fails"); ExecutionDataState { timing, primitive: primitive(node), @@ -454,29 +462,29 @@ fn placement( }); } // An explicit assignment is never silently dropped: one that agrees - // with the fixed timing is kept, one that needs the other timing is + // with the fixed timing is used, one that needs the other timing is // an error. return match assignment.get(node) { - Some(kept) if kept.timing() != placed => Err( + Some(materialized) if materialized.timing() != placed => Err( ExecutionDataStateError::PhysicalPropertiesConflictWithFixedTiming { operator: node.operator.kind_name(), fixed: placed, - assigned: kept, + assigned: materialized, }, ), - Some(kept) => Ok((placed, kept.lifetime())), + Some(materialized) => Ok((placed, materialized.lifetime())), None => Ok((placed, node.lifetime)), }; } Ok(match &node.operator { Operator::ASAP(ASAPOp::SummaryEstimate { .. }) | Operator::ASAP(ASAPOp::EvaluatePopulation { .. }) => match assignment.get(node) { - Some(kept) if kept.timing() == ExecutionTiming::IngestionTime => { + Some(materialized) if materialized.timing() == ExecutionTiming::IngestionTime => { return Err(ExecutionDataStateError::UpstreamNotAtIngestion { operator: node.operator.kind_name(), }) } - Some(kept) => (ExecutionTiming::QueryTime, kept.lifetime()), + Some(materialized) => (ExecutionTiming::QueryTime, materialized.lifetime()), None => (ExecutionTiming::QueryTime, Lifetime::None), }, _ if is_materializable_state_output(&node.operator) || assignment.get(node).is_some() => { @@ -487,7 +495,7 @@ fn placement( } // A summary build that is not materialized runs at query time. None => (ExecutionTiming::QueryTime, Lifetime::None), - Some(kept) => (kept.timing(), kept.lifetime()), + Some(materialized) => (materialized.timing(), materialized.lifetime()), } } _ => (consumer, Lifetime::None), @@ -1031,7 +1039,7 @@ mod tests { const MATERIALIZED_ACROSS: Lifetime = Lifetime::AcrossEvaluations(Medium::Memory); - fn kept(timing: ExecutionTiming, lifetime: Lifetime) -> PhysicalProperties { + fn properties(timing: ExecutionTiming, lifetime: Lifetime) -> PhysicalProperties { PhysicalProperties::new(timing, lifetime).unwrap() } @@ -1071,7 +1079,7 @@ mod tests { ), ] { let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&summary, kept(timing, lifetime)); + assignment.set(&summary, properties(timing, lifetime)); let root = apply_physical_properties(&summary, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); @@ -1249,6 +1257,22 @@ mod tests { ); } + /// Setting a lifetime `None` does not materialize the node, in release + /// builds too: it removes the node's assignment. + #[test] + fn setting_a_lifetime_none_removes_the_assignment() { + let node = max(scan()); + let mut assignment = PhysicalPropertiesAssignment::default(); + assignment.set( + &node, + PhysicalProperties::MATERIALIZED_IN_MEMORY_ACROSS_EVALUATIONS_AT_INGESTION, + ); + assignment.set(&node, PhysicalProperties::NOT_MATERIALIZED_AT_QUERY_TIME); + assert_eq!(assignment.get(&node), None); + assignment.set(&node, PhysicalProperties::NOT_MATERIALIZED_AT_INGESTION); + assert_eq!(assignment.get(&node), None); + } + /// Any node may be materialized, not only a summary state: stored rows /// at ingestion time are read by a query-time consumer, and a node that /// can only run at query time cannot be stored at ingestion time. @@ -1377,7 +1401,7 @@ mod tests { ); let stored = Lifetime::OneEvaluation(Medium::Disk); let mut assignment = PhysicalPropertiesAssignment::default(); - assignment.set(&read, kept(ExecutionTiming::QueryTime, stored)); + assignment.set(&read, properties(ExecutionTiming::QueryTime, stored)); let timed = apply_physical_properties(&read, &assignment, &mut NodeToTimedNodeCache::new()) .unwrap(); assert_eq!(timed.timing, Some(ExecutionTiming::QueryTime)); @@ -1426,7 +1450,7 @@ mod tests { fn ingestion_fixed_node_rejects_mat_at_query() { let fixed = placed_at_ingestion(max(scan())); let root = max(Rc::clone(&fixed)); - let at_query = kept( + let at_query = properties( ExecutionTiming::QueryTime, Lifetime::OneEvaluation(Medium::Memory), ); diff --git a/crates/types/src/physical/properties.rs b/crates/types/src/physical/properties.rs index 2fc33a305..622ccfe5d 100644 --- a/crates/types/src/physical/properties.rs +++ b/crates/types/src/physical/properties.rs @@ -7,7 +7,7 @@ //! | query | `OneEvaluation` | once per evaluation; its readers in that evaluation share it | //! | query | `AcrossEvaluations` | at query time, materialized for later evaluations (a tumbling-window chain that builds its newest window each evaluation) | //! | ingestion | `None` | as data arrives, inside the ingestion work that reads it | -//! | ingestion | `AcrossEvaluations` | as data arrives; kept until a query reads it | +//! | ingestion | `AcrossEvaluations` | as data arrives; materialized until a query reads it | //! | ingestion | `OneEvaluation` | invalid: there is no evaluation at ingestion time | use crate::ir::properties::ExecutionTiming; @@ -27,9 +27,9 @@ pub enum Lifetime { /// Discarded after its reader's execution completes. #[default] None, - /// Kept until every reader within one evaluation finishes. + /// Materialized until every reader within one evaluation finishes. OneEvaluation(Medium), - /// Kept across evaluations, so later evaluations reuse it. + /// Materialized across evaluations, so later evaluations reuse it. AcrossEvaluations(Medium), } @@ -40,7 +40,7 @@ impl Lifetime { self != Self::None } - /// Whether the output is kept across evaluations: a materialized view + /// Whether the output is materialized across evaluations: a materialized view /// that later evaluations reuse. pub fn is_across_evaluations(self) -> bool { matches!(self, Self::AcrossEvaluations(_)) @@ -50,7 +50,7 @@ impl Lifetime { /// A timing and a lifetime that cannot go together. #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] pub enum InvalidPhysicalProperties { - #[error("an ingestion-time output cannot be kept for one evaluation: there is no evaluation at ingestion time")] + #[error("an ingestion-time output cannot be materialized for one evaluation: there is no evaluation at ingestion time")] OneEvaluationAtIngestion, } diff --git a/crates/types/src/stages/physical/graph.rs b/crates/types/src/stages/physical/graph.rs index 62867c49a..c3c6f84a1 100644 --- a/crates/types/src/stages/physical/graph.rs +++ b/crates/types/src/stages/physical/graph.rs @@ -25,7 +25,7 @@ pub enum ReaderConstraint { query_outputs: Vec>, minimum: usize, }, - /// A non-summary node kept for one evaluation (`OneEvaluation`): each node produces an + /// A non-summary node materialized for one evaluation (`OneEvaluation`): each node produces an /// output reference, or has an immediate selected consumer reached by /// at most one query (`query_outputs` as in `MinimumQueryReaders`). HighestSharedOneEvaluation { diff --git a/crates/types/tests/physical_export.rs b/crates/types/tests/physical_export.rs index 3a84d10ec..b29392575 100644 --- a/crates/types/tests/physical_export.rs +++ b/crates/types/tests/physical_export.rs @@ -96,7 +96,7 @@ fn query_time_input_to_ingestion_is_rejected() { } /// A node's timing and lifetime must go together: an ingestion-time output -/// cannot be kept for one evaluation, and a summary build that is not materialized +/// cannot be materialized for one evaluation, and a summary build that is not materialized /// runs at query time. #[test] fn invalid_physical_properties_are_rejected() { @@ -512,7 +512,7 @@ fn every_node_at_query_time_keeps_the_operators_and_stores_nothing() { ]) .unwrap() }; - let kept = workload(timed_at_ingestion()); + let materialized = workload(timed_at_ingestion()); let at_query_time = apply_physical_properties( &plan(), &PhysicalPropertiesAssignment::default(), @@ -520,7 +520,7 @@ fn every_node_at_query_time_keeps_the_operators_and_stores_nothing() { ) .unwrap(); assert_eq!( - kept.with_every_node_at_query_time().unwrap(), + materialized.with_every_node_at_query_time().unwrap(), workload(at_query_time) ); } diff --git a/docs/design_docs/concepts/glossary.md b/docs/design_docs/concepts/glossary.md index b31026963..8b52e6ef6 100644 --- a/docs/design_docs/concepts/glossary.md +++ b/docs/design_docs/concepts/glossary.md @@ -38,7 +38,7 @@ A concrete execution and deployment choice: runtime topology of data lifecycle s ## Materialized view -A node of the physical DAG whose output is kept across evaluations (lifetime `AcrossEvaluations`, at ingestion time or at query time), with how long it is materialized (`retention_ms` on the node). A node materialized for `OneEvaluation` is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. +A node of the physical DAG whose output is materialized across evaluations (lifetime `AcrossEvaluations`, at ingestion time or at query time), with how long it is materialized (`retention_ms` on the node). A node materialized for `OneEvaluation` is not a view: its output is discarded after one evaluation. Code: `MaterializedView`, `PhysicalASAPDAG::materialized_views`. ## Raw data sample diff --git a/docs/design_docs/concepts/post-asap-ir.md b/docs/design_docs/concepts/post-asap-ir.md index 224c6f3e4..fa9beae81 100644 --- a/docs/design_docs/concepts/post-asap-ir.md +++ b/docs/design_docs/concepts/post-asap-ir.md @@ -114,15 +114,15 @@ Materialization ([#509 §Materialization](../proposals/planner-layering.md#mater decides, for each sub-DAG, whether its output is materialized, and if so with which [`PhysicalProperties`](../../../crates/types/src/physical/properties.rs): a timing and a `Lifetime` (#1200). The lifetime is `None` (discarded after its -reader), `OneEvaluation(medium)` (kept until every reader of one evaluation +reader), `OneEvaluation(medium)` (materialized until every reader of one evaluation finishes) or `AcrossEvaluations(medium)` (materialized for later evaluations), with `Medium::Memory` or `Medium::Disk`; an ingestion-time output cannot be materialized for `OneEvaluation`. A [`PhysicalPropertiesAssignment`](../../../crates/types/src/ir/properties/timing.rs) records, per sub-DAG, the properties of its materialized output, named by the node whose output would be materialized. Any node may be named: a summary state, a population, or, as in -#509 Example 4, the tumbling windows a query reads. `set(node, Some(properties))` -keeps one, `set(node, None)` keeps none, and every other sub-DAG is not materialized. +#509 Example 4, the tumbling windows a query reads. `set(node, properties)` +materializes one; every other sub-DAG is not materialized. Stage 2 chooses the assignment. `apply_physical_properties(root, &assignment, &mut NodeToTimedNodeCache)` then writes a timing and a lifetime into every node, top-down: @@ -164,7 +164,7 @@ A node the assignment does not set is not materialized. The test helper and `MaintainPopulation` materialized at ingestion time where the DAG allows it (not filtered, nothing below it that can only run at query time). The test helpers `validate_at_ingestion` and `planned_data_state` use it to check, at -planning time and without keeping anything, that a candidate stays valid +planning time and without materializing anything, that a candidate stays valid when every sub-DAG is materialized at ingestion time. ## Exported DAG @@ -198,7 +198,7 @@ children as edges and no embedded sub-DAGs: validation. Each node also records its `lifetime`, including the medium, so the -deployment knows which outputs to keep, for how long and where; validation +deployment knows which outputs to materialize, for how long and where; validation rejects a timing and lifetime that cannot go together (an ingestion-time output materialized for `OneEvaluation`) and a `SummaryAgg` or `MaintainPopulation` that is not materialized outside query time diff --git a/docs/design_docs/physical-planning-and-deployment.md b/docs/design_docs/physical-planning-and-deployment.md index ac5b261dc..d0da2d084 100644 --- a/docs/design_docs/physical-planning-and-deployment.md +++ b/docs/design_docs/physical-planning-and-deployment.md @@ -53,7 +53,7 @@ decided by a `PhysicalPropertiesAssignment`, as the layer contract below states. a `PhysicalPropertiesAssignment`. `apply_physical_properties` writes every node's `ExecutionTiming` and `Lifetime`: a state materialized at ingestion time and all of its inputs run at ingestion time; readouts, other consumers, and the - other states run at query time. The default assignment keeps nothing; `PlanOutput::physical_asap_dag` applies it + other states run at query time. The default assignment materializes nothing; `PlanOutput::physical_asap_dag` applies it only to nodes the optimization pass left untimed (a pass's own timing, such as Stage 3's ingestion-time tumbling windows, is kept). 3. **Physical compile** (executor) reads the plan's materialized views: each diff --git a/docs/design_docs/proposals/planner-layering-example4-acceptance.md b/docs/design_docs/proposals/planner-layering-example4-acceptance.md index a841cc225..3565c9d27 100644 --- a/docs/design_docs/proposals/planner-layering-example4-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example4-acceptance.md @@ -65,10 +65,10 @@ between B2 (3.611) and B1 (654.54). **Reading physical properties.** The physical DAG records each node's timing and `Lifetime` (#667, #1200). Tests read them through -`planner_layering_common::keeping(p, node)` without the lifetime length or +`planner_layering_common::materializing(p, node)` without the lifetime length or storage medium (`MaterializedAtIngestion`, `MaterializedAtQueryTime`, `NotMaterialized`), and the materialized event-time span through `retention_ms(p, node)`. The IR does not record -retention, so the adapter derives it the way plan selection prices kept +retention, so the adapter derives it the way plan selection prices materialized state: a chain of `N` tumbling windows of width `w` keeps `N·w`, plus one tumbling window while maintained at ingestion time; a whole-window build keeps its window, plus the next one at ingestion time; each plus the offset of the shifts below diff --git a/docs/develop_docs/pre-asap-ir.md b/docs/develop_docs/pre-asap-ir.md index e49f86c63..5f2f5b10e 100644 --- a/docs/develop_docs/pre-asap-ir.md +++ b/docs/develop_docs/pre-asap-ir.md @@ -34,7 +34,7 @@ pub struct OperatorNode { pub schema: Schema, // output schema, derived at construction pub guarantee: Option, // None until accuracy assessment establishes one pub timing: Option, // None until a physical properties assignment is applied - pub lifetime: Lifetime, // None until Stage 2 keeps the node's output + pub lifetime: Lifetime, // None until Stage 2 materializes the node's output } ``` diff --git a/tools/dag-viewer/app.js b/tools/dag-viewer/app.js index fa17338d6..34aed44c5 100644 --- a/tools/dag-viewer/app.js +++ b/tools/dag-viewer/app.js @@ -352,9 +352,9 @@ $('views-meta').innerHTML = selection.materialized_views_error ? `no installable plan: ${esc(selection.materialized_views_error)}` : `${count} materialized view${count === 1 ? '' : 's'} in ${groups.length} group${groups.length === 1 ? '' : 's'} of ${esc(selection.selected_candidate)}` + - (count ? '' : ': nothing is kept across evaluations; every query computes at query time'); + (count ? '' : ': nothing is materialized across evaluations; every query computes at query time'); const tumblingWindowsCell = (g) => (g.tumblingWindows.length > 1 - ? `
${esc(g.tumblingWindows.length)} installed nodes
    ${g.tumblingWindows.map((p) => `
  • node ${esc(p.nodeId)} · ${esc(p.tumblingWindow)} · window ${esc(p.window)} · kept ${esc(p.retention)}
  • `).join('')}
` + ? `
${esc(g.tumblingWindows.length)} installed nodes
    ${g.tumblingWindows.map((p) => `
  • node ${esc(p.nodeId)} · ${esc(p.tumblingWindow)} · window ${esc(p.window)} · materialized ${esc(p.retention)}
  • `).join('')}
` : `node ${esc(g.tumblingWindows[0].nodeId)} · window ${esc(g.tumblingWindows[0].window)}`); $('materializedViews').innerHTML = groups.length ? table( ['Stage 2 node', 'definition', 'kind', 'tumbling windows', 'refresh', 'retention', 'installed', 'Stage 3 cost', 'read by'], diff --git a/tools/dag-viewer/stages.js b/tools/dag-viewer/stages.js index ebe62b60c..fa9e12a15 100644 --- a/tools/dag-viewer/stages.js +++ b/tools/dag-viewer/stages.js @@ -1079,7 +1079,7 @@ function materializedViewRows(doc) { definition: output.coverage.definition_id, kind: summary ? `${kind} · ${summary}` : kind, tumblingWindow, - refresh: output.refresh === 'at_ingestion' ? 'at ingestion' : 'on first read (kept across evaluations)', + refresh: output.refresh === 'at_ingestion' ? 'at ingestion' : 'on first read (materialized across evaluations)', inputs: `${output.inputs.raw_data_windows.length} raw-data window(s)` + (output.inputs.materialized_views.length ? `, views ${output.inputs.materialized_views.join(', ')}` : ''), retention: durationText(output.retention_ms),