algeon_datafusion/native_exec/config/
mod.rs1use std::sync::Arc;
8
9use datafusion::execution::context::TaskContext;
10use query_planning::{
11 capability::{AggregateStrategyExecutionOptions, KeyedHashJoinStrategyOptions},
12 chunk::SourceChunkPlanningOptions,
13 correlation::{QueryId, TraceId},
14 dynamic_filter::DynamicFilterExecutionOptions,
15 execution_contracts::SourceChunkPlanningMode,
16 mode::StatisticalAggregateExecutionMode,
17 policy::PlanningPolicy,
18};
19use query_runtime::{
20 observability::RuntimeObservationConfig,
21 runtime::{
22 AdmittedQueryContext, ExecutionContext, IoLifecycle, LakehouseCacheFillConfig, S3SourceStorageProfile,
23 SourceSchedulerPolicy, SourceStorageProfile,
24 },
25};
26
27pub use self::{
28 chunking::SourceChunking,
29 source_reads::{LakehouseByteCache, LakehouseByteCacheFill},
30};
31use super::{
32 admission::{
33 QueryAdmissionFacts, QueryAdmissionSource, QueryAdmissionTicket, TicketAdmissionContext,
34 invocation_admission_ticket,
35 },
36 metrics::{NativeExecutionMetricsCapture, NativeMetricsCapture},
37};
38#[cfg(feature = "cugraph")]
39use crate::cugraph_sql::GraphBfsSingleflight;
40use crate::{
41 error::{Error, Result},
42 native::{ParquetReadStrategyConfig, S3_STORAGE_PROFILE_ID, ambient_s3_endpoint},
43};
44
45#[derive(Debug, Clone)]
52pub struct AlgeonNativeExecutionConfig {
53 pub(super) source_chunking: SourceChunking,
54 pub(super) source_scheduler_policy: SourceSchedulerPolicy,
55 pub(super) source_chunk_planning_mode: SourceChunkPlanningMode,
56 pub(super) lakehouse_cache_fill_config: LakehouseCacheFillConfig,
57 pub(super) host_output_memory_pool_accounting: bool,
58 pub(super) io_lifecycle: Option<IoLifecycle>,
59 pub(super) statistical_aggregate_execution_mode: StatisticalAggregateExecutionMode,
60 pub(super) planning_policy: PlanningPolicy,
61 pub(super) aggregate_strategy_execution_options: AggregateStrategyExecutionOptions,
62 pub(super) source_chunk_planning_options: SourceChunkPlanningOptions,
63 pub(super) s3_storage: Option<S3SourceStorageProfile>,
64 pub(super) lakehouse_byte_cache: Option<LakehouseByteCache>,
65 pub(super) ambient_s3_endpoint: Option<String>,
68 pub(super) query_admission_source: Option<QueryAdmissionSource>,
69 pub(super) query_admission_ticket: Option<Arc<QueryAdmissionTicket>>,
70 pub(super) query_id: Option<QueryId>,
71 pub(super) trace_id: Option<TraceId>,
72 pub(super) plan_task_mapping_datafusion_shape: Option<String>,
73 pub(super) metrics_capture: Option<NativeMetricsCapture>,
74 pub(super) lakehouse_footer_pruning: bool,
75 #[cfg(feature = "cugraph")]
77 pub(super) bfs_singleflight: GraphBfsSingleflight,
78}
79
80#[derive(Debug)]
82pub(crate) struct AlgeonNativeExecutionContext {
83 pub(super) context: ExecutionContext,
84 pub(super) admission_facts: Option<QueryAdmissionFacts>,
85 pub(super) record_admission_facts: bool,
86 pub(super) _admission_context: Option<AdmittedQueryContext>,
87 pub(super) ticket_context: Option<TicketAdmissionContext>,
88}
89
90mod admission;
91mod chunking;
92mod context;
93mod source_reads;
94#[cfg(test)]
95mod tests;
96
97impl Default for AlgeonNativeExecutionConfig {
98 fn default() -> Self {
99 Self::new(SourceChunking::default())
100 }
101}
102
103impl AlgeonNativeExecutionConfig {
104 pub const AUTO_SIZED_DEVICE_BUDGET_HEADROOM_BYTES: u64 = 500 * 1024 * 1024;
107
108 pub fn new(source_chunking: SourceChunking) -> Self {
112 Self {
113 source_chunking,
114 source_scheduler_policy: SourceSchedulerPolicy::default(),
115 source_chunk_planning_mode: SourceChunkPlanningMode::default(),
116 lakehouse_cache_fill_config: LakehouseCacheFillConfig::default(),
117 host_output_memory_pool_accounting: false,
118 io_lifecycle: None,
119 statistical_aggregate_execution_mode: StatisticalAggregateExecutionMode::default(),
120 planning_policy: PlanningPolicy::default(),
121 aggregate_strategy_execution_options: AggregateStrategyExecutionOptions::default(),
122 source_chunk_planning_options: SourceChunkPlanningOptions::default(),
123 s3_storage: None,
124 lakehouse_byte_cache: None,
125 ambient_s3_endpoint: ambient_s3_endpoint(),
126 query_admission_source: None,
127 query_admission_ticket: None,
128 query_id: None,
129 trace_id: None,
130 plan_task_mapping_datafusion_shape: None,
131 metrics_capture: Some(NativeMetricsCapture::standalone()),
132 lakehouse_footer_pruning: false,
133 #[cfg(feature = "cugraph")]
134 bfs_singleflight: GraphBfsSingleflight::default(),
135 }
136 }
137
138 pub fn with_source_scheduler_policy(mut self, source_scheduler_policy: SourceSchedulerPolicy) -> Self {
140 self.source_scheduler_policy = source_scheduler_policy;
141 self
142 }
143
144 pub fn with_source_chunk_planning_mode(mut self, mode: SourceChunkPlanningMode) -> Self {
146 self.source_chunk_planning_mode = mode;
147 self
148 }
149
150 pub fn with_lakehouse_cache_fill_config(mut self, config: LakehouseCacheFillConfig) -> Self {
152 self.lakehouse_cache_fill_config = config;
153 self
154 }
155
156 pub fn with_host_output_memory_pool_accounting(mut self, enabled: bool) -> Self {
162 self.host_output_memory_pool_accounting = enabled;
163 self
164 }
165
166 #[cfg(feature = "server")]
168 pub(crate) fn with_io_lifecycle(mut self, lifecycle: IoLifecycle) -> Self {
169 self.io_lifecycle = Some(lifecycle);
170 self
171 }
172
173 pub fn with_query_id(mut self, query_id: impl Into<QueryId>) -> Self {
175 self.query_id = Some(query_id.into());
176 self
177 }
178
179 pub(crate) fn with_query_id_if_absent(mut self, query_id: impl Into<QueryId>) -> Self {
181 if self.query_id.is_none() {
182 self.query_id = Some(query_id.into());
183 }
184 self
185 }
186
187 pub fn with_trace_id(mut self, trace_id: impl Into<TraceId>) -> Self {
189 self.trace_id = Some(trace_id.into());
190 self
191 }
192
193 pub(crate) fn with_plan_task_mapping_datafusion_shape(mut self, shape: impl Into<String>) -> Self {
195 let shape = shape.into();
196 if !shape.is_empty() {
197 self.plan_task_mapping_datafusion_shape = Some(shape);
198 }
199 self
200 }
201
202 pub fn query_id(&self) -> Option<&QueryId> {
204 self.query_id.as_ref()
205 }
206
207 pub fn trace_id(&self) -> Option<&TraceId> {
209 self.trace_id.as_ref()
210 }
211
212 pub(crate) fn plan_task_mapping_datafusion_shape(&self) -> Option<&str> {
213 self.plan_task_mapping_datafusion_shape.as_deref()
214 }
215
216 pub(crate) fn new_metrics_capture(&self) -> Option<NativeExecutionMetricsCapture> {
217 self.query_admission_ticket
218 .as_ref()
219 .map(|ticket| ticket.metrics_capture())
220 .or_else(|| self.metrics_capture.as_ref().map(NativeMetricsCapture::new_execution))
221 }
222
223 pub fn runtime_observation_config(&self) -> RuntimeObservationConfig {
225 self.metrics_capture
226 .as_ref()
227 .map_or_else(RuntimeObservationConfig::native_execution, NativeMetricsCapture::runtime_observation_config)
228 }
229
230 pub fn with_lakehouse_footer_pruning(mut self, enabled: bool) -> Self {
233 self.lakehouse_footer_pruning = enabled;
234 self
235 }
236
237 pub fn lakehouse_footer_pruning(&self) -> bool {
239 self.lakehouse_footer_pruning
240 }
241
242 pub fn with_statistical_aggregate_execution_mode(mut self, mode: StatisticalAggregateExecutionMode) -> Self {
252 self.statistical_aggregate_execution_mode = mode;
253 self
254 }
255
256 pub fn with_dynamic_filter_execution_options(mut self, options: DynamicFilterExecutionOptions) -> Self {
262 self.planning_policy.dynamic_filter = options;
263 self
264 }
265
266 pub fn with_keyed_hash_join_strategy_options(mut self, options: KeyedHashJoinStrategyOptions) -> Self {
273 self.planning_policy.keyed_hash_join = options;
274 self
275 }
276
277 pub fn with_aggregate_strategy_execution_options(mut self, options: AggregateStrategyExecutionOptions) -> Self {
284 self.aggregate_strategy_execution_options = options;
285 self
286 }
287
288 pub fn with_source_chunk_planning_options(mut self, options: SourceChunkPlanningOptions) -> Self {
293 self.source_chunk_planning_options = options;
294 self
295 }
296
297 pub fn s3_storage(&self) -> Option<&S3SourceStorageProfile> {
299 self.s3_storage.as_ref()
300 }
301
302 pub(crate) fn source_storage_profiles(&self) -> Vec<SourceStorageProfile> {
305 self.s3_storage.iter().map(|profile| SourceStorageProfile::s3(S3_STORAGE_PROFILE_ID, profile.clone())).collect()
306 }
307
308 pub(crate) fn source_read_strategy(&self) -> ParquetReadStrategyConfig {
310 ParquetReadStrategyConfig::new(
311 self.lakehouse_byte_cache.as_ref(),
312 self.s3_storage.as_ref(),
313 self.ambient_s3_endpoint.as_deref(),
314 )
315 }
316
317 #[cfg(feature = "cugraph")]
318 pub(crate) fn bfs_singleflight(&self) -> &GraphBfsSingleflight {
319 &self.bfs_singleflight
320 }
321
322 pub fn with_s3_storage(mut self, profile: S3SourceStorageProfile) -> Self {
326 self.s3_storage = Some(profile);
327 self
328 }
329
330 pub fn with_lakehouse_byte_cache(mut self, cache: LakehouseByteCache) -> Self {
332 self.lakehouse_byte_cache = Some(cache);
333 self
334 }
335
336 pub fn source_chunking(&self) -> SourceChunking {
338 self.source_chunking
339 }
340
341 pub fn max_source_reads_in_flight(&self) -> usize {
343 self.source_scheduler_policy.max_source_reads_in_flight()
344 }
345
346 pub fn source_scheduler_policy(&self) -> SourceSchedulerPolicy {
348 self.source_scheduler_policy
349 }
350
351 pub fn source_chunk_planning_mode(&self) -> SourceChunkPlanningMode {
353 self.source_chunk_planning_mode
354 }
355
356 pub fn lakehouse_cache_fill_config(&self) -> &LakehouseCacheFillConfig {
358 &self.lakehouse_cache_fill_config
359 }
360
361 pub fn host_output_memory_pool_accounting(&self) -> bool {
364 self.host_output_memory_pool_accounting
365 }
366
367 pub fn statistical_aggregate_execution_mode(&self) -> StatisticalAggregateExecutionMode {
369 self.statistical_aggregate_execution_mode
370 }
371
372 pub fn planning_policy(&self) -> PlanningPolicy {
375 self.planning_policy
376 }
377
378 pub fn aggregate_strategy_execution_options(&self) -> AggregateStrategyExecutionOptions {
380 self.aggregate_strategy_execution_options
381 }
382
383 pub fn source_chunk_planning_options(&self) -> SourceChunkPlanningOptions {
385 self.source_chunk_planning_options
386 }
387
388 pub(crate) fn validate_query_policies(&self) -> Result<()> {
390 self.planning_policy.dynamic_filter.validate().map_err(|error| {
391 Error::from_native(
392 "algeon_datafusion.native_exec.config.validate",
393 "invalid native dynamic-filter execution policy",
394 self.stamp_native_error_correlation(error),
395 )
396 })?;
397 self.planning_policy.keyed_hash_join.validate().map_err(|error| {
398 Error::from_native(
399 "algeon_datafusion.native_exec.config.validate",
400 "invalid native keyed hash-join strategy policy",
401 self.stamp_native_error_correlation(error),
402 )
403 })?;
404 self.aggregate_strategy_execution_options.validate().map_err(|error| {
405 Error::from_native(
406 "algeon_datafusion.native_exec.config.validate",
407 "invalid native aggregate strategy execution policy",
408 self.stamp_native_error_correlation(error),
409 )
410 })?;
411 self.source_chunk_planning_options.validate().map_err(|error| {
412 Error::from_native(
413 "algeon_datafusion.native_exec.config.validate",
414 "invalid native source chunk planning policy",
415 self.stamp_native_error_correlation(error),
416 )
417 })?;
418 Ok(())
419 }
420}