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
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 @@ -1420,8 +1420,8 @@ mod tests {

mod matching {
use super::super::*;
use asap_types::KeyByLabelNames;
use asap_types::{AggregationConfig, PolicyFingerprint, PolicyRegistry};
use promql_utilities::data_model::KeyByLabelNames;
use promql_utilities::query_logics::enums::AggregationType;
use std::collections::HashMap;

Expand Down
54 changes: 17 additions & 37 deletions crates/asap_types/src/aggregation_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::enums::{QueryLanguage, WindowType};
use crate::policy_fingerprint::PolicyFingerprint;
use crate::traits::SerializableToSink;
use crate::utils::normalize_spatial_filter;
use promql_utilities::data_model::KeyByLabelNames;
use crate::KeyByLabelNames;
use promql_utilities::query_logics::enums::AggregationType;

/// Per-aggregation policy carried in the streaming config.
Expand Down Expand Up @@ -395,18 +395,12 @@ mod tests {
/// SAME config as a fixture without it.
#[test]
fn explicit_aggregation_id_in_yaml_is_ignored() {
let with = AggregationConfig::from_yaml_data(
&sample_yaml(true),
None,
QueryLanguage::promql,
)
.expect("parse ok");
let without = AggregationConfig::from_yaml_data(
&sample_yaml(false),
None,
QueryLanguage::promql,
)
.expect("parse ok");
let with =
AggregationConfig::from_yaml_data(&sample_yaml(true), None, QueryLanguage::promql)
.expect("parse ok");
let without =
AggregationConfig::from_yaml_data(&sample_yaml(false), None, QueryLanguage::promql)
.expect("parse ok");
assert_eq!(
with.policy_fingerprint(),
without.policy_fingerprint(),
Expand All @@ -417,18 +411,10 @@ mod tests {
/// Round-tripping the same content yields the same fingerprint.
#[test]
fn fingerprint_is_deterministic_per_content() {
let a = AggregationConfig::from_yaml_data(
&sample_yaml(false),
None,
QueryLanguage::promql,
)
.expect("parse a");
let b = AggregationConfig::from_yaml_data(
&sample_yaml(false),
None,
QueryLanguage::promql,
)
.expect("parse b");
let a = AggregationConfig::from_yaml_data(&sample_yaml(false), None, QueryLanguage::promql)
.expect("parse a");
let b = AggregationConfig::from_yaml_data(&sample_yaml(false), None, QueryLanguage::promql)
.expect("parse b");
assert_eq!(a.policy_fingerprint(), b.policy_fingerprint());
assert_ne!(
a.policy_fingerprint().as_u64(),
Expand All @@ -440,24 +426,18 @@ mod tests {
/// The `policy_fp_u64()` accessor is exactly the fingerprint u64.
#[test]
fn policy_fp_u64_accessor_equals_fingerprint_u64() {
let cfg = AggregationConfig::from_yaml_data(
&sample_yaml(false),
None,
QueryLanguage::promql,
)
.expect("parse");
let cfg =
AggregationConfig::from_yaml_data(&sample_yaml(false), None, QueryLanguage::promql)
.expect("parse");
assert_eq!(cfg.policy_fp_u64(), cfg.policy_fingerprint().as_u64());
}

/// PR 5: `serialize_to_json` no longer emits `aggregationId`.
#[test]
fn serialize_to_json_omits_aggregation_id() {
let cfg = AggregationConfig::from_yaml_data(
&sample_yaml(false),
None,
QueryLanguage::promql,
)
.expect("parse");
let cfg =
AggregationConfig::from_yaml_data(&sample_yaml(false), None, QueryLanguage::promql)
.expect("parse");
let json = cfg.serialize_to_json();
assert!(
json.get("aggregationId").is_none(),
Expand Down
38 changes: 26 additions & 12 deletions crates/asap_types/src/capability_matching.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::cmp::Ordering;
use std::collections::HashMap;

use promql_utilities::data_model::KeyByLabelNames;
use promql_utilities::query_logics::enums::Statistic;
use crate::KeyByLabelNames;
use crate::Statistic;
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};

Expand Down Expand Up @@ -556,7 +556,7 @@ pub fn find_compatible_aggregation(
mod tests {
use super::*;
use crate::utils::normalize_spatial_filter;
use promql_utilities::data_model::KeyByLabelNames;
use crate::KeyByLabelNames;
use std::collections::HashMap;

#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -1018,7 +1018,16 @@ mod tests {
#[test]
fn avg_finds_sum_and_count() {
let sum = make_config(1, "cpu", "Sum", "", 300, "tumbling", &["job"], "");
let cnt = make_config(2, "cpu", "CountMinSketch", "", 300, "tumbling", &["job"], "");
let cnt = make_config(
2,
"cpu",
"CountMinSketch",
"",
300,
"tumbling",
&["job"],
"",
);
let mut configs = HashMap::new();
configs.insert(sum.policy_fp_u64(), sum);
configs.insert(cnt.policy_fp_u64(), cnt);
Expand All @@ -1039,7 +1048,16 @@ mod tests {
fn avg_different_windows_rejected() {
let sum = make_config(1, "cpu", "Sum", "", 300, "tumbling", &["job"], "");
// Count config has different window_size — must be rejected
let cnt = make_config(2, "cpu", "CountMinSketch", "", 900, "tumbling", &["job"], "");
let cnt = make_config(
2,
"cpu",
"CountMinSketch",
"",
900,
"tumbling",
&["job"],
"",
);
let mut configs = HashMap::new();
configs.insert(sum.policy_fp_u64(), sum);
configs.insert(cnt.policy_fp_u64(), cnt);
Expand Down Expand Up @@ -1204,8 +1222,7 @@ mod tests {
StorageBackend::SketchStore,
StorageBackend::DoubleWrite,
] {
let backends =
compatible_storage_backends(Statistic::Sum, AccuracyTarget::Exact, cfg);
let backends = compatible_storage_backends(Statistic::Sum, AccuracyTarget::Exact, cfg);
assert_eq!(
backends,
vec![StorageBackend::GorillaObjectStore],
Expand All @@ -1225,11 +1242,8 @@ mod tests {
StorageBackend::GorillaObjectStore,
StorageBackend::DoubleWrite,
] {
let backends = compatible_storage_backends(
Statistic::Quantile,
AccuracyTarget::Approximate,
cfg,
);
let backends =
compatible_storage_backends(Statistic::Quantile, AccuracyTarget::Approximate, cfg);
assert_eq!(
backends,
vec![
Expand Down
76 changes: 76 additions & 0 deletions crates/asap_types/src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,85 @@
use std::fmt;
use std::str::FromStr;
use tracing::debug;

// Re-export AggregationType from promql_utilities (defined there to avoid circular deps).
pub use promql_utilities::query_logics::enums::AggregationType;

/// The scalar value a serving-time query wants out of an already-built
/// accumulator: "given a live `AggregateCore` implementation, which
/// number do you want?" Every accumulator's `AggregateCore::query_statistic`
/// dispatches on this. Distinct from L3's `AggIntent` (a planning-time
/// IR node carrying accuracy targets, column refs, φ, k) — nothing at
/// L3/L4 reaches down to a live Rust struct's fields, so `Statistic` has
/// no upstream ASAPController equivalent; it's this workspace's own
/// serving-time vocabulary.
///
/// Formerly `promql_utilities::query_logics::enums::Statistic` — moved
/// here because its real center of gravity (`compatible_agg_types`,
/// `QueryRequirements`, capability matching) already lived in this
/// crate, and `asap_types` — not `data_plane` — is the shared foundation
/// both `control_plane`'s ecosystem and `data_plane` can depend on
/// without a cycle.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum Statistic {
Count,
Sum,
Cardinality,
Increase,
Rate,
Min,
Max,
Quantile,
Topk,
}

impl fmt::Display for Statistic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
debug!("Formatting Statistic: {:?}", self);
match self {
Statistic::Count => write!(f, "count"),
Statistic::Sum => write!(f, "sum"),
Statistic::Cardinality => write!(f, "cardinality"),
Statistic::Increase => write!(f, "increase"),
Statistic::Rate => write!(f, "rate"),
Statistic::Min => write!(f, "min"),
Statistic::Max => write!(f, "max"),
Statistic::Quantile => write!(f, "quantile"),
Statistic::Topk => write!(f, "topk"),
}
}
}

#[allow(clippy::should_implement_trait)]
impl Statistic {
pub fn from_str(s: &str) -> Option<Self> {
debug!("Parsing Statistic from string: {}", s);
match s.to_lowercase().as_str() {
"count" => Some(Statistic::Count),
"sum" => Some(Statistic::Sum),
"cardinality" => Some(Statistic::Cardinality),
"increase" => Some(Statistic::Increase),
"rate" => Some(Statistic::Rate),
"min" => Some(Statistic::Min),
"max" => Some(Statistic::Max),
"quantile" => Some(Statistic::Quantile),
"topk" => Some(Statistic::Topk),
_ => None,
}
}
}

impl FromStr for Statistic {
type Err = ();

/// Parse a statistic from a string (case-insensitive).
/// Use `s.parse::<Statistic>()` or `Statistic::from_str(s)`.
fn from_str(s: &str) -> Result<Self, Self::Err> {
debug!("FromStr trait parsing Statistic: {}", s);
Statistic::from_str(s).ok_or(())
}
}

#[derive(clap::ValueEnum, Clone, Copy, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum QueryLanguage {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
//! A sorted, set-algebra-bearing label-name key.
//!
//! Formerly `promql_utilities::data_model::key_by_label_names` — moved
//! here for the same reason as [`crate::Statistic`]: `asap_types`
//! (`AggregationConfig::grouping_labels`, `PolicyFingerprint`,
//! `PolicyRegistry`, `capability_matching`) is its real center of
//! gravity and the shared foundation both `control_plane`'s ecosystem
//! and `data_plane` can depend on without a cycle. Closer to a runtime
//! index key than a planning IR node — ASAPController's
//! `QueryExpr::Aggregate.by` is the nearest relative in spirit, but
//! carries positional `ColumnId`s, not a sorted, deduplicated label-name
//! set with `Vec`-style set algebra.

use serde::{Deserialize, Serialize};
use tracing::debug;

Expand Down
2 changes: 2 additions & 0 deletions crates/asap_types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod aggregation_config;
pub mod capability_matching;
pub mod enums;
pub mod key_by_label_names;
pub mod policy_fingerprint;
pub mod policy_registry;
pub mod query_requirements;
Expand All @@ -15,6 +16,7 @@ pub use capability_matching::{
ENGINE_ID_THANOS_QUERY,
};
pub use enums::*;
pub use key_by_label_names::KeyByLabelNames;
pub use policy_fingerprint::PolicyFingerprint;
pub use policy_registry::PolicyRegistry;
pub use query_requirements::*;
Expand Down
Loading