query_runtime/runtime/query_service/
config.rs1use std::time::{Duration, Instant};
8
9use query_planning::{
10 capability::AggregateStrategyExecutionOptions,
11 chunk::SourceChunkPlanningOptions,
12 error::{QueryError, QueryErrorCode, Result},
13 execution_contracts::{MemoryControlPolicy, SourceChunkPlanningMode},
14 mode::StatisticalAggregateExecutionMode,
15 policy::PlanningPolicy,
16};
17
18use crate::runtime::{
19 LakehouseCacheFillConfig, SourceSchedulerPolicy, SourceStorageProfile, object_store::SourceObjectStoreRegistry,
20};
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct QueueBounds {
25 pub max_waiters: usize,
29 pub max_wait: Duration,
31}
32
33impl QueueBounds {
34 pub(crate) const fn canonical_default() -> Self {
40 Self { max_waiters: 64, max_wait: Duration::from_secs(30) }
41 }
42
43 pub(crate) fn wait_deadline(&self, start: Instant, requested: Option<Instant>) -> Option<Instant> {
48 let configured = start.checked_add(self.max_wait);
49 match (requested, configured) {
50 (Some(requested), Some(configured)) => Some(requested.min(configured)),
51 (requested, configured) => requested.or(configured),
52 }
53 }
54
55 pub(in crate::runtime) fn validate(&self) -> Result<()> {
56 validate_nonzero_config_field("queue_bounds.max_waiters", self.max_waiters == 0)?;
57 validate_nonzero_config_field("queue_bounds.max_wait", self.max_wait.is_zero())
58 }
59}
60
61impl Default for QueueBounds {
62 fn default() -> Self {
63 Self::canonical_default()
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct QueryExecutionConfig {
70 pub lakehouse_cache_fill: LakehouseCacheFillConfig,
72 pub source_storage_profiles: Vec<SourceStorageProfile>,
74 pub source_scheduler_policy: SourceSchedulerPolicy,
76 pub source_chunk_planning_mode: SourceChunkPlanningMode,
78 pub statistical_aggregate_execution_mode: StatisticalAggregateExecutionMode,
81 pub planning_policy: PlanningPolicy,
84 pub aggregate_strategy_execution_options: AggregateStrategyExecutionOptions,
86 pub source_chunk_planning_options: SourceChunkPlanningOptions,
88 pub max_source_chunk_bytes: u64,
91 pub max_row_groups_per_chunk: usize,
93 pub max_retry_attempts: usize,
95 pub min_retry_chunk_row_groups: usize,
97}
98
99impl QueryExecutionConfig {
100 pub(in crate::runtime) fn validate(&self) -> Result<()> {
101 self.lakehouse_cache_fill.validate()?;
102 self.source_scheduler_policy.validate()?;
103 self.planning_policy.validate()?;
104 self.aggregate_strategy_execution_options.validate()?;
105 self.source_chunk_planning_options.validate()?;
106 validate_nonzero_config_field("max_source_chunk_bytes", self.max_source_chunk_bytes == 0)?;
107 validate_nonzero_config_field("max_row_groups_per_chunk", self.max_row_groups_per_chunk == 0)?;
108 validate_nonzero_config_field("max_retry_attempts", self.max_retry_attempts == 0)?;
109 validate_nonzero_config_field("min_retry_chunk_row_groups", self.min_retry_chunk_row_groups == 0)?;
110 SourceObjectStoreRegistry::validate_profiles(&self.source_storage_profiles)
111 }
112
113 pub(in crate::runtime) fn memory_policy_for_admitted_query(&self, device_budget_bytes: u64) -> MemoryControlPolicy {
114 MemoryControlPolicy {
115 device_budget_bytes,
116 max_source_chunk_bytes: self.max_source_chunk_bytes,
117 max_row_groups_per_chunk: self.max_row_groups_per_chunk,
118 max_retry_attempts: self.max_retry_attempts,
119 min_retry_chunk_row_groups: self.min_retry_chunk_row_groups,
120 }
121 }
122}
123
124impl Default for QueryExecutionConfig {
125 fn default() -> Self {
126 Self {
127 lakehouse_cache_fill: LakehouseCacheFillConfig::default(),
128 source_storage_profiles: Vec::new(),
129 source_scheduler_policy: SourceSchedulerPolicy::default(),
130 source_chunk_planning_mode: SourceChunkPlanningMode::default(),
131 statistical_aggregate_execution_mode: StatisticalAggregateExecutionMode::default(),
132 planning_policy: PlanningPolicy::default(),
133 aggregate_strategy_execution_options: AggregateStrategyExecutionOptions::default(),
134 source_chunk_planning_options: SourceChunkPlanningOptions::default(),
135 max_source_chunk_bytes: MemoryControlPolicy::DEFAULT_MAX_SOURCE_CHUNK_BYTES,
136 max_row_groups_per_chunk: MemoryControlPolicy::DEFAULT_MAX_ROW_GROUPS_PER_CHUNK,
137 max_retry_attempts: MemoryControlPolicy::DEFAULT_MAX_RETRY_ATTEMPTS,
138 min_retry_chunk_row_groups: MemoryControlPolicy::DEFAULT_MIN_RETRY_CHUNK_ROW_GROUPS,
139 }
140 }
141}
142
143fn validate_nonzero_config_field(field: &'static str, is_zero: bool) -> Result<()> {
144 if is_zero {
145 return Err(QueryError::new(
146 QueryErrorCode::InvalidConfiguration,
147 "query_engine.query_service.config.validate",
148 "query service config field must be greater than zero",
149 )
150 .with_fact("field", field)
151 .with_fact("reason", "zero"));
152 }
153 Ok(())
154}