Skip to content
Draft
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
6 changes: 3 additions & 3 deletions crates/asap-aware-mapping/src/pass/major.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl OptimizationPass for MajorPass {
demand,
lifecycle.now_ms,
lifecycle.horizon,
lifecycle.capabilities,
models.capabilities,
models.cost,
)
.map_err(OptimizeError::LifecycleSelection)?;
Expand Down Expand Up @@ -132,7 +132,7 @@ impl OptimizationPass for MajorPass {
},
lifecycle.now_ms,
lifecycle.horizon,
lifecycle.capabilities,
models.capabilities,
models.cost,
)
.map_err(|source| OptimizeError::LifecycleAssembly {
Expand Down Expand Up @@ -171,7 +171,7 @@ impl OptimizationPass for MajorPass {
},
lifecycle.now_ms,
lifecycle.horizon,
lifecycle.capabilities,
models.capabilities,
models.cost,
)
.map_err(|source| OptimizeError::LifecycleAssembly {
Expand Down
18 changes: 14 additions & 4 deletions crates/asap-aware-mapping/src/pass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub struct PlanningModels<'a> {
pub cost: &'a dyn CostModel,
pub accuracy: &'a dyn AccuracyModel,
pub evidence: &'a dyn AccuracyEvidenceProvider,
pub capabilities: SummaryMaintenanceLifecycleCapabilities,
}

impl<'a> PlanningModels<'a> {
Expand All @@ -60,6 +61,7 @@ impl<'a> PlanningModels<'a> {
cost,
accuracy,
evidence,
capabilities: SummaryMaintenanceLifecycleCapabilities::ALL,
}
}

Expand All @@ -71,6 +73,7 @@ impl<'a> PlanningModels<'a> {
cost: &DEFAULT_COST_MODEL,
accuracy: &DEFAULT_ACCURACY_MODEL,
evidence: &NO_ACCURACY_EVIDENCE,
capabilities: SummaryMaintenanceLifecycleCapabilities::ALL,
}
}

Expand All @@ -88,6 +91,14 @@ impl<'a> PlanningModels<'a> {
self.evidence = evidence;
self
}

pub fn with_capabilities(
mut self,
capabilities: SummaryMaintenanceLifecycleCapabilities,
) -> Self {
self.capabilities = capabilities;
self
}
}

/// Supplying this asks the pass to also decide summary maintenance versus raw
Expand All @@ -99,15 +110,13 @@ pub struct LifecycleInput {
pub now_ms: u64,
/// Seconds. Required to turn recurring demand into a finite total.
pub horizon: Option<Horizon>,
pub capabilities: SummaryMaintenanceLifecycleCapabilities,
}

impl LifecycleInput {
pub fn new(now_ms: u64, capabilities: SummaryMaintenanceLifecycleCapabilities) -> Self {
pub fn new(now_ms: u64) -> Self {
Self {
now_ms,
horizon: None,
capabilities,
}
}

Expand All @@ -123,7 +132,8 @@ pub struct OptimizationInput<'a> {
pub workload: &'a ParsedWorkload,
pub models: PlanningModels<'a>,
/// Every plan carries the maintenance-versus-recomputation decision, so
/// the planning clock and runtime capabilities are always required.
/// the planning clock is always required. Runtime capabilities are in
/// `models` with the deployment's cost and accuracy models.
pub lifecycle: LifecycleInput,
}

Expand Down
5 changes: 2 additions & 3 deletions crates/integration-tests/tests/operator_design_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,7 @@ async fn batch_planning_replaces_and_shares_summary_operators() {
use asap_aware_mapping::cost_model::{Cost, DefaultCostModel};
use asap_aware_mapping::pass::PlanningModels;
use asap_aware_mapping::{
CostModel, CostRate, LifecycleInput, SummaryMaintenanceLifecycleCapabilities,
SummaryMaintenanceLifecycleCostInputs,
CostModel, CostRate, LifecycleInput, SummaryMaintenanceLifecycleCostInputs,
};
use asap_physical_operators::{
physical_planner::{compile, InputContract},
Expand Down Expand Up @@ -336,7 +335,7 @@ async fn batch_planning_replaces_and_shares_summary_operators() {
&workload,
FrontendInput::Sql { catalog: &catalog },
PlanningModels::builtin().with_cost(&Costs),
LifecycleInput::new(0, SummaryMaintenanceLifecycleCapabilities::default()),
LifecycleInput::new(0),
))
.await
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/planner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ pub struct UserInput<'a> {
pub workload: &'a PlanningWorkload,
pub frontend_specific: FrontendInput<'a>,
pub models: PlanningModels<'a>,
/// Planning clock and runtime capabilities for the
/// maintenance-versus-recomputation decision every plan carries.
/// Planning clock for the maintenance-versus-recomputation decision every
/// plan carries. Runtime capabilities are supplied with `models`.
pub lifecycle: LifecycleInput,
/// `None` uses [`MajorPass`]. A black-box caller never sets this.
pub pass: Option<&'a dyn OptimizationPass>,
Expand Down
54 changes: 46 additions & 8 deletions crates/planner/tests/e2e_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use asap_aware_mapping::pass::{
OptimizationInput, OptimizationPass, OptimizeError, PlanOutput, PlanningModels,
};
use asap_aware_mapping::replacement::default_strategies_with_evidence;
use asap_aware_mapping::{
search_workload_with_targets, Horizon, LifecycleInput, SummaryMaintenanceLifecycleCapabilities,
};
use asap_aware_mapping::{search_workload_with_targets, Horizon, LifecycleInput};
use asap_frontend_sql::{lower_sql_dialect, SqlCatalog};
use asap_planner::{e2e_plan, FrontendInput, PlanError, UserInput, UserInputError};
use asap_types::pre_asap::schema::{DataType, Field, Schema};
Expand Down Expand Up @@ -43,7 +41,7 @@ fn batch(sql: &str) -> BatchEntry {
/// The planning clock and default capabilities, no horizon: the least a
/// caller can supply.
fn lifecycle() -> LifecycleInput {
LifecycleInput::new(NOW_MS, SummaryMaintenanceLifecycleCapabilities::default())
LifecycleInput::new(NOW_MS)
}

fn lineitem_catalog() -> SqlCatalog {
Expand Down Expand Up @@ -165,6 +163,49 @@ async fn builtin_cost_model_cannot_price_lifecycles_and_falls_back_to_raw_recomp
}
}

/// Runtime capabilities are deployment inputs alongside the cost and
/// accuracy models, while LifecycleInput carries only the planning clock.
#[tokio::test]
async fn deployment_inputs_control_lifecycle_capabilities() {
let workload = sql_workload(
vec![batch("SELECT COUNT(DISTINCT l_orderkey) FROM lineitem")],
None,
);
let catalog = lineitem_catalog();
let models = PlanningModels::builtin().with_capabilities(
asap_aware_mapping::SummaryMaintenanceLifecycleCapabilities {
supports_ephemeral: true,
supports_prepared: false,
supports_shared: false,
supports_continuously_maintained: false,
},
);

let output = e2e_plan(UserInput::new(
&workload,
FrontendInput::Sql { catalog: &catalog },
models,
lifecycle(),
))
.await
.expect("workload remains plannable with restricted capabilities");

assert!(output
.plans
.iter()
.flat_map(|plan| &plan.plan.deployments)
.all(
|deployment| deployment.alternatives.iter().all(|alternative| {
!matches!(
alternative.summary_maintenance_lifecycle,
asap_types::post_asap::SummaryMaintenanceLifecycle::Prepared { .. }
| asap_types::post_asap::SummaryMaintenanceLifecycle::Shared { .. }
| asap_types::post_asap::SummaryMaintenanceLifecycle::ContinuouslyMaintained
) || alternative.rejection.is_some()
})
));
}

/// A repeating SQL query reaches the optimizer. `lower_sql_batch` walks
/// `query_batch` alone, so driving the frontend through it would drop exactly
/// the entries whose recurrence the lifecycle stage reads.
Expand Down Expand Up @@ -338,10 +379,7 @@ fn rejects_disagreeing_planning_clocks() {
histograms: None,
},
PlanningModels::builtin(),
LifecycleInput::new(
NOW_MS + 1,
SummaryMaintenanceLifecycleCapabilities::default(),
),
LifecycleInput::new(NOW_MS + 1),
);

assert!(matches!(
Expand Down
5 changes: 2 additions & 3 deletions crates/planner/tests/summary_sharing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use asap_aware_mapping::pass::{PlanOutput, PlanningModels};
use asap_aware_mapping::replacement::{default_size_params, DEFAULT_DELTA};
use asap_aware_mapping::{
CostModel, CostRate, DefaultCostModel, Horizon, LifecycleInput, SummaryMaintenanceCapabilities,
SummaryMaintenanceLifecycleCapabilities, SummaryMaintenanceLifecycleCostInputs,
SummaryMaintenanceLifecycleCostInputs,
};
use asap_frontend_sql::SqlCatalog;
use asap_planner::{e2e_plan, FrontendInput, UserInput};
Expand Down Expand Up @@ -103,8 +103,7 @@ fn repeating(query: &str, epsilon: f64) -> RepeatingEntry {
}

fn lifecycle() -> LifecycleInput {
LifecycleInput::new(NOW_MS, SummaryMaintenanceLifecycleCapabilities::default())
.with_horizon(Horizon(HORIZON_S))
LifecycleInput::new(NOW_MS).with_horizon(Horizon(HORIZON_S))
}

fn promql_workload(queries: &[(&str, f64)]) -> PlanningWorkload {
Expand Down
Loading