1use std::collections::HashMap;
16use std::fmt;
17use std::num::NonZeroUsize;
18use std::sync::{Arc, RwLock};
19
20use async_trait::async_trait;
21use catalog::CatalogManagerRef;
22use common_base::Plugins;
23use common_function::aggrs::aggr_wrapper::fix_order::FixStateUdafOrderingAnalyzer;
24use common_function::function_factory::ScalarFunctionFactory;
25use common_function::function_registry::FUNCTION_REGISTRY;
26use common_function::handlers::{
27 FlowServiceHandlerRef, ProcedureServiceHandlerRef, TableMutationHandlerRef,
28};
29use common_function::state::FunctionState;
30use common_stat::get_total_memory_bytes;
31use common_telemetry::warn;
32use datafusion::catalog::TableFunction;
33use datafusion::dataframe::DataFrame;
34use datafusion::error::Result as DfResult;
35use datafusion::execution::SessionStateBuilder;
36use datafusion::execution::context::{QueryPlanner, SessionConfig, SessionContext, SessionState};
37use datafusion::execution::memory_pool::{
38 GreedyMemoryPool, MemoryConsumer, MemoryLimit, MemoryPool, MemoryReservation,
39 TrackConsumersPool,
40};
41use datafusion::physical_optimizer::PhysicalOptimizerRule;
42use datafusion::physical_optimizer::optimizer::PhysicalOptimizer;
43use datafusion::physical_optimizer::sanity_checker::SanityCheckPlan;
44use datafusion::physical_plan::ExecutionPlan;
45use datafusion::physical_planner::{DefaultPhysicalPlanner, ExtensionPlanner, PhysicalPlanner};
46use datafusion_expr::{AggregateUDF, LogicalPlan as DfLogicalPlan, WindowUDF};
47use datafusion_optimizer::Analyzer;
48use datafusion_optimizer::analyzer::function_rewrite::ApplyFunctionRewrites;
49use datafusion_optimizer::optimizer::Optimizer;
50use partition::manager::PartitionRuleManagerRef;
51use promql::extension_plan::PromExtensionPlanner;
52use session::context::QueryContextRef;
53use table::TableRef;
54use table::table::adapter::DfTableProviderAdapter;
55
56use crate::QueryEngineContext;
57use crate::dist_plan::{
58 DistExtensionPlanner, DistPlannerAnalyzer, DistPlannerOptions, DynFilterRegistryManager,
59 MergeSortExtensionPlanner, RemoteDynFilterReceiverExtensionPlanner,
60 RemoteDynFilterRegistryLease,
61};
62use crate::metrics::{QUERY_MEMORY_POOL_REJECTED_TOTAL, QUERY_MEMORY_POOL_USAGE_BYTES};
63use crate::optimizer::ExtensionAnalyzerRule;
64use crate::optimizer::const_normalization::ConstNormalizationRule;
65use crate::optimizer::constant_term::MatchesConstantTermOptimizer;
66use crate::optimizer::count_nest_aggr::CountNestAggrRule;
67use crate::optimizer::count_wildcard::CountWildcardToTimeIndexRule;
68use crate::optimizer::global_limit::EnsureGlobalLimitForFetch;
69use crate::optimizer::json_type_concretize::JsonTypeConcretizeRule;
70use crate::optimizer::parallelize_scan::ParallelizeScan;
71use crate::optimizer::pass_distribution::PassDistribution;
72use crate::optimizer::promql_tsid_narrow_join::PromqlTsidNarrowJoin;
73use crate::optimizer::remove_duplicate::RemoveDuplicate;
74use crate::optimizer::scan_hint::ScanHintRule;
75use crate::optimizer::string_normalization::StringNormalizationRule;
76use crate::optimizer::transcribe_atat::TranscribeAtatRule;
77use crate::optimizer::type_conversion::TypeConversionRule;
78use crate::optimizer::windowed_sort::WindowedSortPhysicalRule;
79use crate::options::QueryOptions as QueryOptionsNew;
80use crate::query_engine::DefaultSerializer;
81use crate::query_engine::options::QueryOptions;
82use crate::query_engine::runtime::{
83 DefaultQueryRuntimeProvider, QueryRuntimeContext, QueryRuntimeProviderRef,
84};
85use crate::range_select::planner::RangeSelectPlanner;
86use crate::region_query::RegionQueryHandlerRef;
87
88#[derive(Clone)]
90pub struct QueryEngineState {
91 df_context: SessionContext,
92 catalog_manager: CatalogManagerRef,
93 dyn_filter_registry_manager: Arc<DynFilterRegistryManager>,
94 function_state: Arc<FunctionState>,
95 scalar_functions: Arc<RwLock<HashMap<String, ScalarFunctionFactory>>>,
96 aggr_functions: Arc<RwLock<HashMap<String, AggregateUDF>>>,
97 table_functions: Arc<RwLock<HashMap<String, Arc<TableFunction>>>>,
98 extension_rules: Vec<Arc<dyn ExtensionAnalyzerRule + Send + Sync>>,
99 plugins: Plugins,
100}
101
102impl fmt::Debug for QueryEngineState {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 f.debug_struct("QueryEngineState")
105 .field("state", &self.df_context.state())
106 .finish()
107 }
108}
109
110impl QueryEngineState {
111 #[allow(clippy::too_many_arguments)]
112 pub fn new(
113 catalog_list: CatalogManagerRef,
114 partition_rule_manager: Option<PartitionRuleManagerRef>,
115 region_query_handler: Option<RegionQueryHandlerRef>,
116 table_mutation_handler: Option<TableMutationHandlerRef>,
117 procedure_service_handler: Option<ProcedureServiceHandlerRef>,
118 flow_service_handler: Option<FlowServiceHandlerRef>,
119 with_dist_planner: bool,
120 plugins: Plugins,
121 options: QueryOptionsNew,
122 ) -> Self {
123 Self::try_new(
124 catalog_list,
125 partition_rule_manager,
126 region_query_handler,
127 table_mutation_handler,
128 procedure_service_handler,
129 flow_service_handler,
130 with_dist_planner,
131 plugins,
132 options,
133 )
134 .expect("Failed to build query engine state")
135 }
136
137 #[allow(clippy::too_many_arguments)]
138 pub fn try_new(
139 catalog_list: CatalogManagerRef,
140 partition_rule_manager: Option<PartitionRuleManagerRef>,
141 region_query_handler: Option<RegionQueryHandlerRef>,
142 table_mutation_handler: Option<TableMutationHandlerRef>,
143 procedure_service_handler: Option<ProcedureServiceHandlerRef>,
144 flow_service_handler: Option<FlowServiceHandlerRef>,
145 with_dist_planner: bool,
146 plugins: Plugins,
147 options: QueryOptionsNew,
148 ) -> DfResult<Self> {
149 let total_memory = get_total_memory_bytes().max(0) as u64;
150 let memory_pool_size = options.memory_pool_size.resolve(total_memory) as usize;
151 let runtime_provider = plugins
152 .get::<QueryRuntimeProviderRef>()
153 .unwrap_or_else(|| Arc::new(DefaultQueryRuntimeProvider));
154 let mut session_config = SessionConfig::new().with_create_default_catalog_and_schema(false);
155 if options.parallelism > 0 {
156 session_config = session_config.with_target_partitions(options.parallelism);
157 }
158 if options.allow_query_fallback {
159 session_config
160 .options_mut()
161 .extensions
162 .insert(DistPlannerOptions {
163 allow_query_fallback: true,
164 });
165 }
166
167 session_config
170 .options_mut()
171 .execution
172 .skip_physical_aggregate_schema_check = true;
173
174 let runtime_context = QueryRuntimeContext::new(&options, memory_pool_size);
175 runtime_provider.configure_session_config(runtime_context, &mut session_config);
176 let runtime_builder = DefaultQueryRuntimeProvider::runtime_env_builder(runtime_context);
177 let runtime_env = runtime_provider.build_runtime_env(runtime_context, runtime_builder)?;
178
179 let mut extension_rules = Vec::new();
181
182 extension_rules.insert(0, Arc::new(TypeConversionRule) as _);
184 extension_rules.push(Arc::new(CountNestAggrRule) as _);
185
186 let mut analyzer = Analyzer::new();
188 analyzer.rules.insert(0, Arc::new(TranscribeAtatRule));
189 analyzer.rules.insert(0, Arc::new(StringNormalizationRule));
190 analyzer
191 .rules
192 .insert(0, Arc::new(CountWildcardToTimeIndexRule));
193 analyzer.rules.push(Arc::new(ConstNormalizationRule));
194
195 analyzer.rules.insert(
199 0,
200 Arc::new(ApplyFunctionRewrites::new(
201 FUNCTION_REGISTRY.function_rewrites(),
202 )),
203 );
204
205 if with_dist_planner {
206 analyzer.rules.push(Arc::new(DistPlannerAnalyzer));
207 }
208 analyzer.rules.push(Arc::new(FixStateUdafOrderingAnalyzer));
209
210 let mut optimizer = Optimizer::new();
211 optimizer.rules.push(Arc::new(ScanHintRule));
212 optimizer.rules.push(Arc::new(JsonTypeConcretizeRule));
213
214 let mut physical_optimizer = PhysicalOptimizer::new();
216 physical_optimizer
218 .rules
219 .insert(5, Arc::new(ParallelizeScan));
220 physical_optimizer
222 .rules
223 .insert(6, Arc::new(PassDistribution));
224 physical_optimizer
226 .rules
227 .insert(7, Arc::new(PromqlTsidNarrowJoin));
228 physical_optimizer.rules.insert(
230 8,
231 Arc::new(datafusion::physical_optimizer::enforce_sorting::EnforceSorting {}),
232 );
233 physical_optimizer
235 .rules
236 .push(Arc::new(WindowedSortPhysicalRule));
237 physical_optimizer
242 .rules
243 .push(Arc::new(MatchesConstantTermOptimizer));
244 physical_optimizer
245 .rules
246 .push(Arc::new(EnsureGlobalLimitForFetch));
247 physical_optimizer.rules.push(Arc::new(RemoveDuplicate));
249 Self::remove_physical_optimizer_rule(
251 &mut physical_optimizer.rules,
252 SanityCheckPlan {}.name(),
253 );
254 physical_optimizer.rules.push(Arc::new(SanityCheckPlan {}));
255
256 let session_state = SessionStateBuilder::new()
257 .with_config(session_config)
258 .with_runtime_env(runtime_env)
259 .with_default_features()
260 .with_analyzer_rules(analyzer.rules)
261 .with_serializer_registry(Arc::new(DefaultSerializer))
262 .with_query_planner(Arc::new(DfQueryPlanner::new(
263 catalog_list.clone(),
264 partition_rule_manager,
265 region_query_handler.clone(),
266 options.enable_per_region_metrics,
267 )))
268 .with_optimizer_rules(optimizer.rules)
269 .with_physical_optimizer_rules(physical_optimizer.rules)
270 .build();
271
272 let df_context = SessionContext::new_with_state(session_state);
273 register_function_aliases(&df_context);
274
275 Ok(Self {
276 df_context,
277 catalog_manager: catalog_list,
278 dyn_filter_registry_manager: Arc::new(DynFilterRegistryManager::default()),
279 function_state: Arc::new(FunctionState {
280 table_mutation_handler,
281 procedure_service_handler,
282 flow_service_handler,
283 }),
284 aggr_functions: Arc::new(RwLock::new(HashMap::new())),
285 table_functions: Arc::new(RwLock::new(HashMap::new())),
286 extension_rules,
287 plugins,
288 scalar_functions: Arc::new(RwLock::new(HashMap::new())),
289 })
290 }
291
292 fn remove_physical_optimizer_rule(
293 rules: &mut Vec<Arc<dyn PhysicalOptimizerRule + Send + Sync>>,
294 name: &str,
295 ) {
296 rules.retain(|rule| rule.name() != name);
297 }
298
299 pub fn optimize_by_extension_rules(
301 &self,
302 plan: DfLogicalPlan,
303 context: &QueryEngineContext,
304 ) -> DfResult<DfLogicalPlan> {
305 self.extension_rules
306 .iter()
307 .try_fold(plan, |acc_plan, rule| {
308 rule.analyze(acc_plan, context, self.session_state().config_options())
309 })
310 }
311
312 pub fn optimize_logical_plan(&self, plan: DfLogicalPlan) -> DfResult<DfLogicalPlan> {
314 self.session_state().optimize(&plan)
315 }
316
317 pub fn scalar_function(&self, function_name: &str) -> Option<ScalarFunctionFactory> {
319 self.scalar_functions
320 .read()
321 .unwrap()
322 .get(function_name)
323 .cloned()
324 }
325
326 pub fn scalar_names(&self) -> Vec<String> {
328 self.scalar_functions
329 .read()
330 .unwrap()
331 .keys()
332 .cloned()
333 .collect()
334 }
335
336 pub fn aggr_function(&self, function_name: &str) -> Option<AggregateUDF> {
338 self.aggr_functions
339 .read()
340 .unwrap()
341 .get(function_name)
342 .cloned()
343 }
344
345 pub fn aggr_names(&self) -> Vec<String> {
347 self.aggr_functions
348 .read()
349 .unwrap()
350 .keys()
351 .cloned()
352 .collect()
353 }
354
355 pub fn table_function(&self, function_name: &str) -> Option<Arc<TableFunction>> {
357 self.table_functions
358 .read()
359 .unwrap()
360 .get(function_name)
361 .cloned()
362 }
363
364 pub fn table_function_names(&self) -> Vec<String> {
366 self.table_functions
367 .read()
368 .unwrap()
369 .keys()
370 .cloned()
371 .collect()
372 }
373
374 pub fn register_scalar_function(&self, func: ScalarFunctionFactory) {
377 let name = func.name().to_string();
378 let x = self
379 .scalar_functions
380 .write()
381 .unwrap()
382 .insert(name.clone(), func);
383
384 if x.is_some() {
385 warn!("Already registered scalar function '{name}'");
386 }
387 }
388
389 pub fn register_aggr_function(&self, func: AggregateUDF) {
398 let name = func.name().to_string();
399 let x = self
400 .aggr_functions
401 .write()
402 .unwrap()
403 .insert(name.clone(), func);
404 assert!(
405 x.is_none(),
406 "Already registered aggregate function '{name}'"
407 );
408 }
409
410 pub fn register_table_function(&self, func: Arc<TableFunction>) {
411 let name = func.name();
412 let x = self
413 .table_functions
414 .write()
415 .unwrap()
416 .insert(name.to_string(), func.clone());
417
418 if x.is_some() {
419 warn!("Already registered table function '{name}'");
420 }
421 }
422
423 pub fn register_window_function(&self, func: WindowUDF) {
428 self.df_context.register_udwf(func);
429 }
430
431 pub fn catalog_manager(&self) -> &CatalogManagerRef {
432 &self.catalog_manager
433 }
434
435 pub fn dyn_filter_registry_manager(&self) -> Arc<DynFilterRegistryManager> {
436 self.dyn_filter_registry_manager.clone()
437 }
438
439 pub fn acquire_remote_dyn_filter_registry_lease(
440 &self,
441 query_ctx: &QueryContextRef,
442 ) -> Option<RemoteDynFilterRegistryLease> {
443 let query_id = query_ctx.remote_query_id_value()?;
444 Some(
445 self.dyn_filter_registry_manager
446 .clone()
447 .acquire_lease(query_id),
448 )
449 }
450
451 pub fn function_state(&self) -> Arc<FunctionState> {
452 self.function_state.clone()
453 }
454
455 pub fn table_mutation_handler(&self) -> Option<&TableMutationHandlerRef> {
457 self.function_state.table_mutation_handler.as_ref()
458 }
459
460 pub fn procedure_service_handler(&self) -> Option<&ProcedureServiceHandlerRef> {
462 self.function_state.procedure_service_handler.as_ref()
463 }
464
465 pub(crate) fn disallow_cross_catalog_query(&self) -> bool {
466 self.plugins
467 .map::<QueryOptions, _, _>(|x| x.disallow_cross_catalog_query)
468 .unwrap_or(false)
469 }
470
471 pub fn session_state(&self) -> SessionState {
472 self.df_context.state()
473 }
474
475 pub fn read_table(&self, table: TableRef) -> DfResult<DataFrame> {
477 self.df_context
478 .read_table(Arc::new(DfTableProviderAdapter::new(table)))
479 }
480}
481
482struct DfQueryPlanner {
483 physical_planner: DefaultPhysicalPlanner,
484}
485
486impl fmt::Debug for DfQueryPlanner {
487 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488 f.debug_struct("DfQueryPlanner").finish()
489 }
490}
491
492#[async_trait]
493impl QueryPlanner for DfQueryPlanner {
494 async fn create_physical_plan(
495 &self,
496 logical_plan: &DfLogicalPlan,
497 session_state: &SessionState,
498 ) -> DfResult<Arc<dyn ExecutionPlan>> {
499 self.physical_planner
500 .create_physical_plan(logical_plan, session_state)
501 .await
502 }
503}
504
505const SCALAR_FUNCTION_ALIASES: &[(&str, &str)] = &[
507 ("upper", "ucase"),
508 ("lower", "lcase"),
509 ("ceil", "ceiling"),
510 ("substr", "mid"),
511 ("random", "rand"),
512];
513
514const AGGREGATE_FUNCTION_ALIASES: &[(&str, &str)] =
516 &[("stddev_pop", "std"), ("var_pop", "variance")];
517
518fn register_function_aliases(ctx: &SessionContext) {
523 let state = ctx.state();
524
525 for (target, alias) in SCALAR_FUNCTION_ALIASES {
526 if let Some(func) = state.scalar_functions().get(*target) {
527 let aliased = func.as_ref().clone().with_aliases([*alias]);
528 ctx.register_udf(aliased);
529 }
530 }
531
532 for (target, alias) in AGGREGATE_FUNCTION_ALIASES {
533 if let Some(func) = state.aggregate_functions().get(*target) {
534 let aliased = func.as_ref().clone().with_aliases([*alias]);
535 ctx.register_udaf(aliased);
536 }
537 }
538}
539
540impl DfQueryPlanner {
541 fn new(
542 catalog_manager: CatalogManagerRef,
543 partition_rule_manager: Option<PartitionRuleManagerRef>,
544 region_query_handler: Option<RegionQueryHandlerRef>,
545 enable_per_region_metrics: bool,
546 ) -> Self {
547 let mut planners: Vec<Arc<dyn ExtensionPlanner + Send + Sync>> = vec![
548 Arc::new(PromExtensionPlanner),
549 Arc::new(RangeSelectPlanner),
550 Arc::new(RemoteDynFilterReceiverExtensionPlanner),
551 ];
552 if let (Some(region_query_handler), Some(partition_rule_manager)) =
553 (region_query_handler, partition_rule_manager)
554 {
555 planners.push(Arc::new(DistExtensionPlanner::new(
556 catalog_manager,
557 partition_rule_manager,
558 region_query_handler,
559 enable_per_region_metrics,
560 )));
561 planners.push(Arc::new(MergeSortExtensionPlanner {}));
562 }
563 Self {
564 physical_planner: DefaultPhysicalPlanner::with_extension_planners(planners),
565 }
566 }
567}
568
569#[derive(Debug)]
574pub(super) struct MetricsMemoryPool {
575 inner: Arc<TrackConsumersPool<GreedyMemoryPool>>,
576}
577
578impl MetricsMemoryPool {
579 const TOP_CONSUMERS_TO_REPORT: usize = 5;
581
582 pub(super) fn new(limit: usize) -> Self {
583 Self {
584 inner: Arc::new(TrackConsumersPool::new(
585 GreedyMemoryPool::new(limit),
586 NonZeroUsize::new(Self::TOP_CONSUMERS_TO_REPORT).unwrap(),
587 )),
588 }
589 }
590
591 #[inline]
592 fn update_metrics(&self) {
593 QUERY_MEMORY_POOL_USAGE_BYTES.set(self.inner.reserved() as i64);
594 }
595}
596
597impl MemoryPool for MetricsMemoryPool {
598 fn register(&self, consumer: &MemoryConsumer) {
599 self.inner.register(consumer);
600 }
601
602 fn unregister(&self, consumer: &MemoryConsumer) {
603 self.inner.unregister(consumer);
604 }
605
606 fn grow(&self, reservation: &MemoryReservation, additional: usize) {
607 self.inner.grow(reservation, additional);
608 self.update_metrics();
609 }
610
611 fn shrink(&self, reservation: &MemoryReservation, shrink: usize) {
612 self.inner.shrink(reservation, shrink);
613 self.update_metrics();
614 }
615
616 fn try_grow(
617 &self,
618 reservation: &MemoryReservation,
619 additional: usize,
620 ) -> datafusion_common::Result<()> {
621 let result = self.inner.try_grow(reservation, additional);
622 if result.is_err() {
623 QUERY_MEMORY_POOL_REJECTED_TOTAL.inc();
624 }
625 self.update_metrics();
626 result
627 }
628
629 fn reserved(&self) -> usize {
630 self.inner.reserved()
631 }
632
633 fn memory_limit(&self) -> MemoryLimit {
634 self.inner.memory_limit()
635 }
636}
637
638#[cfg(test)]
639mod tests {
640 use std::sync::atomic::{AtomicBool, Ordering};
641
642 use common_base::Plugins;
643 use common_base::memory_limit::MemoryLimit;
644 use common_base::readable_size::ReadableSize;
645 use datafusion::error::DataFusionError;
646 use datafusion::execution::memory_pool::{GreedyMemoryPool, MemoryLimit as DfMemoryLimit};
647 use datafusion::execution::runtime_env::{RuntimeEnv, RuntimeEnvBuilder};
648 use session::context::QueryContext;
649
650 use super::*;
651 use crate::options::QueryOptions;
652 use crate::query_engine::runtime::{QueryRuntimeProvider, QueryRuntimeProviderRef};
653
654 fn new_query_engine_state() -> QueryEngineState {
655 new_query_engine_state_with(Plugins::default(), QueryOptions::default())
656 }
657
658 fn new_query_engine_state_with(plugins: Plugins, options: QueryOptions) -> QueryEngineState {
659 QueryEngineState::new(
660 catalog::memory::new_memory_catalog_manager().unwrap(),
661 None,
662 None,
663 None,
664 None,
665 None,
666 false,
667 plugins,
668 options,
669 )
670 }
671
672 struct TestRuntimeProvider {
673 build_called: AtomicBool,
674 configure_called: AtomicBool,
675 }
676
677 impl TestRuntimeProvider {
678 fn new() -> Self {
679 Self {
680 build_called: AtomicBool::new(false),
681 configure_called: AtomicBool::new(false),
682 }
683 }
684 }
685
686 impl QueryRuntimeProvider for TestRuntimeProvider {
687 fn configure_session_config(
688 &self,
689 ctx: QueryRuntimeContext<'_>,
690 config: &mut SessionConfig,
691 ) {
692 assert_eq!(ctx.resolved_memory_pool_size, 1024);
693 self.configure_called.store(true, Ordering::SeqCst);
694 *config = config.clone().with_target_partitions(7);
695 }
696
697 fn build_runtime_env(
698 &self,
699 ctx: QueryRuntimeContext<'_>,
700 builder: RuntimeEnvBuilder,
701 ) -> DfResult<Arc<RuntimeEnv>> {
702 assert_eq!(ctx.resolved_memory_pool_size, 1024);
703 self.build_called.store(true, Ordering::SeqCst);
704 builder
705 .with_memory_pool(Arc::new(GreedyMemoryPool::new(2048)))
706 .build()
707 .map(Arc::new)
708 }
709 }
710
711 struct ErrorRuntimeProvider;
712
713 impl QueryRuntimeProvider for ErrorRuntimeProvider {
714 fn build_runtime_env(
715 &self,
716 _ctx: QueryRuntimeContext<'_>,
717 _builder: RuntimeEnvBuilder,
718 ) -> DfResult<Arc<RuntimeEnv>> {
719 Err(DataFusionError::Execution("runtime provider error".into()))
720 }
721 }
722
723 #[test]
724 fn query_runtime_default_provider_keeps_bounded_memory_pool() {
725 let state = new_query_engine_state_with(
726 Plugins::default(),
727 QueryOptions {
728 memory_pool_size: MemoryLimit::Size(ReadableSize(1024)),
729 ..Default::default()
730 },
731 );
732
733 assert!(matches!(
734 state
735 .session_state()
736 .runtime_env()
737 .memory_pool
738 .memory_limit(),
739 DfMemoryLimit::Finite(1024)
740 ));
741 }
742
743 #[test]
744 fn query_runtime_provider_from_plugins_builds_runtime_env() {
745 let plugins = Plugins::default();
746 let provider = Arc::new(TestRuntimeProvider::new());
747 plugins.insert::<QueryRuntimeProviderRef>(provider.clone());
748
749 let state = new_query_engine_state_with(
750 plugins,
751 QueryOptions {
752 memory_pool_size: MemoryLimit::Size(ReadableSize(1024)),
753 ..Default::default()
754 },
755 );
756
757 assert!(provider.build_called.load(Ordering::SeqCst));
758 assert!(matches!(
759 state
760 .session_state()
761 .runtime_env()
762 .memory_pool
763 .memory_limit(),
764 DfMemoryLimit::Finite(2048)
765 ));
766 }
767
768 #[test]
769 fn query_runtime_provider_from_plugins_configures_session_config() {
770 let plugins = Plugins::default();
771 let provider = Arc::new(TestRuntimeProvider::new());
772 plugins.insert::<QueryRuntimeProviderRef>(provider.clone());
773
774 let state = new_query_engine_state_with(
775 plugins,
776 QueryOptions {
777 memory_pool_size: MemoryLimit::Size(ReadableSize(1024)),
778 ..Default::default()
779 },
780 );
781
782 assert!(provider.configure_called.load(Ordering::SeqCst));
783 assert_eq!(7, state.session_state().config().target_partitions());
784 }
785
786 #[test]
787 fn query_runtime_provider_error_is_returned_by_try_new() {
788 let plugins = Plugins::default();
789 plugins.insert::<QueryRuntimeProviderRef>(Arc::new(ErrorRuntimeProvider));
790
791 let err = QueryEngineState::try_new(
792 catalog::memory::new_memory_catalog_manager().unwrap(),
793 None,
794 None,
795 None,
796 None,
797 None,
798 false,
799 plugins,
800 QueryOptions::default(),
801 )
802 .unwrap_err();
803
804 assert!(
805 matches!(err, DataFusionError::Execution(message) if message == "runtime provider error")
806 );
807 }
808
809 #[test]
810 fn query_engine_state_reuses_query_scoped_dyn_filter_registry_lease() {
811 let state = new_query_engine_state();
812 let query_ctx = QueryContext::arc();
813
814 let first = state
815 .acquire_remote_dyn_filter_registry_lease(&query_ctx)
816 .unwrap();
817 let second = state
818 .acquire_remote_dyn_filter_registry_lease(&query_ctx)
819 .unwrap();
820
821 assert!(first.ptr_eq(&second));
822 assert_eq!(state.dyn_filter_registry_manager().registry_count(), 1);
823 assert_eq!(
824 first.registry().query_id(),
825 query_ctx.remote_query_id_value().unwrap()
826 );
827 }
828
829 #[test]
830 fn query_engine_state_relies_on_query_context_remote_query_id_contract() {
831 let state = new_query_engine_state();
832 let query_ctx = QueryContext::arc();
833
834 assert!(query_ctx.remote_query_id_value().is_some());
835
836 let lease = state
837 .acquire_remote_dyn_filter_registry_lease(&query_ctx)
838 .unwrap();
839
840 assert_eq!(
841 lease.registry().query_id(),
842 query_ctx.remote_query_id_value().unwrap()
843 );
844 assert_eq!(state.dyn_filter_registry_manager().registry_count(), 1);
845 }
846
847 #[test]
848 fn query_engine_state_separates_registries_for_different_query_contexts() {
849 let state = new_query_engine_state();
850 let first_query_ctx = QueryContext::arc();
851 let second_query_ctx = QueryContext::arc();
852
853 let first = state
854 .acquire_remote_dyn_filter_registry_lease(&first_query_ctx)
855 .unwrap();
856 let second = state
857 .acquire_remote_dyn_filter_registry_lease(&second_query_ctx)
858 .unwrap();
859
860 assert!(!first.ptr_eq(&second));
861 assert_eq!(state.dyn_filter_registry_manager().registry_count(), 2);
862 assert_eq!(
863 first.registry().query_id(),
864 first_query_ctx.remote_query_id_value().unwrap()
865 );
866 assert_eq!(
867 second.registry().query_id(),
868 second_query_ctx.remote_query_id_value().unwrap()
869 );
870 }
871}