Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions control_plane/docs/design.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion control_plane/src/asap_tier_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ fn collect_agg_intents(expr: &QueryExpr, out: &mut Vec<AggIntent>) {
collect_agg_intents(child, out);
}
QueryExpr::Scan { .. } | QueryExpr::Ref { .. } => {}
// A-variants lifted in Batch 2 of the legacy_expr migration. They
// A-variants lifted in Batch 2 of the relational migration. They
// carry no AggIntent themselves — recurse into their children to
// find Aggregates further down the tree.
QueryExpr::Filter { child, .. }
Expand Down
8 changes: 4 additions & 4 deletions control_plane/src/intent_algebra/agg_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub enum AggIntent {
// captures the intent so the routing decision is layered above intent.
//
// Note: `histogram_quantile(φ, …)` is NOT an L3 intent — it's a PromQL
// /MetricsQL language-level operator. Per Step γ5 of the legacy_expr
// /MetricsQL language-level operator. Per Step γ5 of the relational
// migration, the PromQL parser substitutes it directly into a plain
// `Aggregate { Quantile(φ) }` (which lowers to
// `AggIntent::Quantile { q, accuracy }`); bucket-aware handling is a
Expand Down Expand Up @@ -336,10 +336,10 @@ fn quantile_suffix(q: f64) -> String {

// ── AggIntent helpers ────────────────────────────────────────────────────────
//
// Step γ7: relocated from `legacy_expr.rs` (where they were free fns
// operating on the canonical re-exported `AggIntent`). `legacy_expr`
// Step γ7: relocated from `relational.rs` (where they were free fns
// operating on the canonical re-exported `AggIntent`). `relational`
// re-exports them during the legacy-IR retirement; consumers migrate to
// `intent_algebra::*` paths and the re-exports drop with `legacy_expr`.
// `intent_algebra::*` paths and the re-exports drop with `relational`.

/// Two instances of this aggregation can be merged
/// (`agg(A ∪ B) = combine(agg(A), agg(B))`). `Avg` is the only
Expand Down
8 changes: 4 additions & 4 deletions control_plane/src/intent_algebra/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! Our canonical L3 IR (`query_expr::QueryExpr`) already commits to
//! positional column identity — `Aggregate.by: Vec<ColumnId>` — exactly
//! like RisingWave's `InputRef`. What was missing was the *pass* that
//! produces it: resolution was smeared into `legacy_to_canonical::convert`
//! produces it: resolution was smeared into `lower_to_canonical::convert`
//! with a hardcoded synthesized `(ts, value)` schema, so any query
//! referencing a real label / column name (`price`, `host`, …) errored.
//!
Expand Down Expand Up @@ -46,11 +46,11 @@
//! ## Where it sits
//!
//! Today the Binder runs at the L2→L3 (legacy → canonical) conversion
//! boundary — `legacy_to_canonical::convert_root` calls it. Once the
//! boundary — `lower_to_canonical::convert_root` calls it. Once the
//! legacy IR is retired it moves into the `core::lower` L1→L2→L3 passes
//! proper (the `lower_*(ast, schema)` signatures in design.md §6).

use crate::intent_algebra::legacy_expr::QueryExpr as LQueryExpr;
use crate::intent_algebra::relational::QueryExpr as LQueryExpr;
use crate::intent_algebra::schema::{Column, DataType, Schema};

/// The DB / source-schema metadata source from design.md §6 "three
Expand Down Expand Up @@ -192,7 +192,7 @@ fn collect_referenced_columns(tree: &LQueryExpr) -> Vec<String> {
#[cfg(test)]
mod tests {
use super::*;
use crate::intent_algebra::legacy_expr::{
use crate::intent_algebra::relational::{
AggFunc, AggItem, ColumnRef as LColumnRef, PartitionKeys, QueryExpr as LQueryExpr,
SourceSpec,
};
Expand Down
20 changes: 10 additions & 10 deletions control_plane/src/intent_algebra/column_resolution.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Schema-driven column resolution for the legacy `QueryExpr` IR
//! (Step β of the legacy_expr migration).
//! (Step β of the relational migration).
//!
//! Step α (PR #138) replaced the legacy `AggIntent` enum with the canonical
//! [`crate::intent_algebra::agg_intent::AggIntent`]. The legacy IR still
//! uses [`crate::intent_algebra::legacy_expr::ColumnRef::Named(String)`] for
//! uses [`crate::intent_algebra::relational::ColumnRef::Named(String)`] for
//! column references; the canonical IR uses positional
//! [`crate::intent_algebra::schema::ColumnId`] resolved against a per-node
//! [`crate::intent_algebra::schema::Schema`].
Expand All @@ -29,7 +29,7 @@
//!
//! ## Why a synthesized default
//!
//! The legacy_expr migration plan's "Synthesise from metric name:
//! The relational migration plan's "Synthesise from metric name:
//! `(ts, value, *labels)`" decision applies here. There is no
//! `SchemaCatalog` in the controller today, so the source leaf has to
//! produce a schema purely from the metric / table name. This module
Expand All @@ -41,7 +41,7 @@
use thiserror::Error;

use crate::intent_algebra::agg_intent::AggIntent;
use crate::intent_algebra::legacy_expr::{ColumnRef, QueryExpr, SourceSpec};
use crate::intent_algebra::relational::{ColumnRef, QueryExpr, SourceSpec};
use crate::intent_algebra::schema::{Column, ColumnId, DataType, Schema};

/// Errors returned by [`resolve_column_ref`] / [`resolve_column_refs`].
Expand Down Expand Up @@ -81,7 +81,7 @@ pub enum ResolveError {
/// representation for "any number of label columns whose names are
/// data-dependent." That's tracked as a Step γ TODO at the module level.
///
/// Per the legacy_expr migration plan's "Synthesise from metric name:
/// Per the relational migration plan's "Synthesise from metric name:
/// `(ts, value, *labels)`" decision — minus the `*labels` part the
/// canonical schema model can't express today.
pub fn infer_source_schema(_metric_or_table_name: &str) -> Schema {
Expand Down Expand Up @@ -170,11 +170,11 @@ pub fn resolve_column_refs(

/// Slice-flavoured variant of [`resolve_column_ref`] over a list of
/// `Vec<String>` GROUP BY keys (the shape carried by
/// `legacy_expr::QueryExpr::Aggregate.keys`). Mirrors
/// `relational::QueryExpr::Aggregate.keys`). Mirrors
/// [`resolve_column_refs`] but skips the `ColumnRef::Named` wrapping —
/// the legacy `Aggregate.keys` field is already a `Vec<String>`.
///
/// Used by `legacy_to_canonical::convert` to translate a legacy
/// Used by `lower_to_canonical::convert` to translate a legacy
/// `Aggregate.keys: Vec<String>` into the canonical `by: Vec<ColumnId>`.
pub fn resolve_named_keys(
keys: &[String],
Expand Down Expand Up @@ -295,7 +295,7 @@ pub fn output_schema_for_aggregate(
#[cfg(test)]
mod tests {
use super::*;
use crate::intent_algebra::legacy_expr::SourceSpec;
use crate::intent_algebra::relational::SourceSpec;

fn src(name: &str) -> QueryExpr {
QueryExpr::Source(SourceSpec { name: name.into() })
Expand All @@ -315,8 +315,8 @@ mod tests {
#[test]
fn root_schema_via_walk() {
let expr = QueryExpr::Filter {
pred: crate::intent_algebra::legacy_expr::ScalarExpr::Literal(
crate::intent_algebra::legacy_expr::LiteralValue::Bool(true),
pred: crate::intent_algebra::relational::ScalarExpr::Literal(
crate::intent_algebra::relational::LiteralValue::Bool(true),
),
input: Box::new(src("cpu_usage")),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! The legacy Layer-2 → canonical L3 IR converter.
//! The Layer-2 → canonical L3 IR converter.
//!
//! Recursively converts a *whole* `legacy_expr::QueryExpr` tree (the raw
//! Recursively converts a *whole* `relational::QueryExpr` tree (the raw
//! Layer-2 relational IR the `query_parser` front ends emit) into a
//! *whole* canonical `query_expr::QueryExpr` tree. This is the single
//! entry the parse path routes through — [`convert_root`].
//!
//! ## Variant mapping
//!
//! | legacy `QueryExpr` | canonical `QueryExpr` |
//! | relational `QueryExpr` | canonical `QueryExpr` |
//! |---|---|
//! | `Source(spec)` | `Scan { TimeSeries, label_filters: [], schema }` |
//! | `Ref(name)` | `Ref { name }` |
Expand All @@ -24,15 +24,14 @@
//! | `SetOp` | `SetOp` |
//! | `Sort` | `Sort` |
//! | `Limit` | `Limit` |
//! | `LetBinding` | `LetBinding` (legacy `body` → canonical `child`) |
//! | `LetBinding` | `LetBinding` (relational `body` → canonical `child`)|
//! | `PromQLSubquery` | `Subquery` |
//! | `BinaryOp` | `BinaryOp` |
//!
//! The single-statistic sketchable `Aggregate` fusion was, before the
//! legacy-IR retirement, a separate `legacy_lower` pass that produced
//! intermediate `SketchAgg` / `WindowedAgg` legacy Layer-3 nodes. Those
//! variants are gone — the fusion is now done directly in canonical
//! terms inside the [`convert`] `Aggregate` arm.
//! The single-statistic sketchable `Aggregate` fusion (`Window`-swap,
//! `Partition` wrap, `StdDev` / `Variance` fan-out) is done directly in
//! canonical terms inside the [`convert`] `Aggregate` arm — there is no
//! intermediate sketch-fused L2-or-L3 IR.
//!
//! ## Schema threading
//!
Expand All @@ -41,7 +40,7 @@
//! complete and self-contained (`(ts, value)` plus every referenced
//! name), so threading the root schema down is correct except for the
//! nested-schema-transform case (an `Aggregate` below another
//! `Aggregate`), which the legacy stack also doesn't handle — proper
//! `Aggregate`), which the L2→L3 lowering also doesn't handle — proper
//! bottom-up schema flow lands with the canonical `output_schema_in`
//! wiring downstream.

Expand All @@ -56,7 +55,7 @@ use crate::intent_algebra::binder::Binder;
use crate::intent_algebra::column_resolution::{
resolve_named_keys, ResolveError,
};
use crate::intent_algebra::legacy_expr::{
use crate::intent_algebra::relational::{
AggFunc, ColumnRef as LColumnRef, PartitionKeys as LPartitionKeys, QueryExpr as LQueryExpr,
ScalarExpr as LScalarExpr,
};
Expand Down Expand Up @@ -479,7 +478,7 @@ fn convert_column_ref(c: &LColumnRef) -> CColumnRef {
/// `StdDev` / `Variance` fan-out (the caller wraps the pair in a `Merge`
/// of sibling sketch aggregates).
fn agg_func_to_intents(func: &AggFunc) -> Vec<AggIntent> {
use crate::intent_algebra::legacy_expr::{
use crate::intent_algebra::relational::{
default_cardinality, default_frequency, default_quantile,
};
match func {
Expand Down Expand Up @@ -517,7 +516,7 @@ fn agg_func_to_intents(func: &AggFunc) -> Vec<AggIntent> {
#[cfg(test)]
mod tests {
use super::*;
use crate::intent_algebra::legacy_expr::{
use crate::intent_algebra::relational::{
AggFunc, AggItem, ColumnRef as LColumnRef, ProjectItem as LProjectItem, SourceSpec,
};

Expand Down Expand Up @@ -815,7 +814,7 @@ mod tests {
offset: 0,
input: Box::new(LQueryExpr::Filter {
pred: LScalarExpr::Literal(
crate::intent_algebra::legacy_expr::LiteralValue::Bool(true),
crate::intent_algebra::relational::LiteralValue::Bool(true),
),
input: Box::new(LQueryExpr::Window {
duration: Duration::from_secs(60),
Expand Down
46 changes: 17 additions & 29 deletions control_plane/src/intent_algebra/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,20 @@ pub mod lower;
pub mod query_expr;
pub mod schema;

// Refactor 2026-05 (`refactor/controller-layered-cleanup`): the
// pre-existing legacy L2 relational IR formerly at
// `controller/src/algebra/expr.rs` lives here while a separate follow-up
// unifies it with the canonical `query_expr` module above. It still
// carries the `QueryExpr` type the `query_parser` modules emit and the
// planner / allocator / physical planner modules consume today.
// The **Layer-2 relational IR** — the `QueryExpr` tree the `query_parser`
// front ends emit (`promql.rs` / `sql.rs`). Formerly `legacy_expr`; it is
// the real, current L2 IR, not legacy debt. The planner / allocator /
// physical planner still consume it directly while their migration onto
// the canonical L3 `query_expr` types is in progress.
pub mod column_resolution;
pub mod legacy_expr;
pub mod relational;

// Step γ7 keystone: the legacy → canonical full-tree converter. The
// `query_parser` entry points emit raw Layer-2 trees and route them
// through `convert_root`, which first folds them into the sketch-fused
// legacy Layer-3 form (the former `legacy_lower` pass, now private to
// this module) and then maps that onto the canonical IR.
pub mod legacy_to_canonical;
pub use legacy_to_canonical::{convert as convert_legacy, convert_root, ConvertError};
// The L2 → canonical-L3 lowering. The `query_parser` entry points emit a
// raw `relational::QueryExpr` tree and route it through `convert_root`,
// which lowers it (single-statistic sketchable `Aggregate` fusion folded
// in) onto the canonical IR.
pub mod lower_to_canonical;
pub use lower_to_canonical::{convert, convert_root, ConvertError};

// Step γ7: the L3 Binder — name resolution as an explicit pass. Produces
// the complete self-contained `Schema` every `ColumnId` indexes into;
Expand All @@ -120,22 +118,12 @@ pub use query_expr::{
};
pub use schema::{cse_reuse_is_legal, Column, ColumnId, CseError, DataType, Schema};

// Step β plumbing: schema-driven column resolution helpers used by the
// legacy planning stack (`optimizer/engine.rs`, `physical/{allocator,
// planner, stage_split}.rs`, `query_parser/*`) to carry an inherited
// `Schema` alongside every legacy `QueryExpr` traversal. Consumers call
// `resolve_column_ref` at the point
// where they need a positional `ColumnId` — Step γ migrates variants
// one at a time onto the canonical positional form.
// Schema-driven column-resolution helpers used by the planning stack
// (`optimizer/engine.rs`, `physical/{allocator,planner,stage_split}.rs`,
// `query_parser/*`) to carry an inherited `Schema` alongside a
// `relational::QueryExpr` traversal. Consumers call `resolve_column_ref`
// at the point where they need a positional `ColumnId`.
pub use column_resolution::{
infer_schema_for_root, infer_source_schema, output_schema_for_aggregate, resolve_column_ref,
resolve_column_refs, resolve_named_keys, ResolveError,
};

// Step γ7 (PR 13): the four γ1–γ4 one-way "approach (c)" bridges
// (`aggregate_bridge`, `topk_bridge`, `windowed_agg_bridge`,
// `sketch_agg_bridge`) were deleted. They returned canonical-shape data
// *minus the child* — useful only as a non-composable migration aid
// while consumers still pattern-matched legacy variants. Every consumer
// now runs on the canonical IR via the composable `legacy_to_canonical`
// converter, so the bridges had zero remaining call sites.
Loading