1use std::any::Any;
16use std::sync::Arc;
17
18use common_query::request::{
19 DynFilterPayload, INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY, InitialDynFilterReg,
20 InitialDynFilterRegs, InitialDynFilterSnapshot, REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
21};
22use datafusion::physical_plan::filter_pushdown::PushedDown;
23use datafusion_common::Result;
24use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRecursion};
25use datafusion_expr::ColumnarValue;
26use datafusion_physical_expr::PhysicalExpr;
27use datafusion_physical_expr::expressions::{
28 Column, DynamicFilterPhysicalExpr, InListExpr, Literal, lit,
29};
30use datafusion_physical_expr::scalar_subquery::ScalarSubqueryExpr;
31use datafusion_physical_expr::utils::collect_columns;
32use session::context::{QueryContext, QueryContextRef};
33use store_api::storage::RegionId;
34
35use crate::dist_plan::filter_id::build_remote_dyn_filter_id;
36use crate::dist_plan::{
37 FilterId, QueryDynFilterRegistry, RemoteDynFilterProducerId, Subscriber, SubscriberRegistration,
38};
39use crate::region_query::RegionQueryTarget;
40
41#[derive(Debug, Clone)]
42pub(crate) struct CapturedDynFilter {
43 filter_id: FilterId,
44 initial_registration: InitialDynFilterReg,
45 pub(crate) alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
46 scalar_subquery_filter: Option<Arc<dyn PhysicalExpr>>,
56}
57
58#[derive(Debug, Clone)]
59pub(crate) struct RemoteDynFilterPushdown {
60 pub(crate) captured_dyn_filters: Vec<CapturedDynFilter>,
61 pub(crate) pushed_down: Vec<PushedDown>,
63}
64
65pub(crate) fn capture_remote_dyn_filters_for_pushdown(
69 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
70 first_producer_local_ordinal: usize,
71 accepted: &[CapturedDynFilter],
72 parent_filters: Vec<Arc<dyn datafusion::physical_plan::PhysicalExpr>>,
73) -> RemoteDynFilterPushdown {
74 let mut pushed_down = Vec::with_capacity(parent_filters.len());
75 let mut captured_dyn_filters = Vec::new();
76
77 for (index, filter) in parent_filters.into_iter().enumerate() {
78 let producer_local_ordinal = first_producer_local_ordinal + index;
79 let captured = if let Some(alive_dyn_filter) = downcast_dynamic_filter(filter.clone()) {
80 build_captured_dyn_filter(
81 remote_dyn_filter_producer_id,
82 producer_local_ordinal,
83 alive_dyn_filter,
84 )
85 .map(|captured| (captured, PushedDown::Yes))
86 } else if is_scalar_subquery_filter(&filter) {
87 build_scalar_subquery_dyn_filter(
90 remote_dyn_filter_producer_id,
91 producer_local_ordinal,
92 filter,
93 )
94 .map(|captured| (captured, PushedDown::No))
95 } else {
96 pushed_down.push(PushedDown::No);
97 continue;
98 };
99
100 match captured {
101 Ok((captured_dyn_filter, pushdown)) => {
102 pushed_down.push(pushdown);
103 captured_dyn_filters.push(captured_dyn_filter);
104 }
105 Err(error) => {
106 common_telemetry::warn!(error; "Remote dyn filter is not pushed down because initial registration cannot be built");
107 pushed_down.push(PushedDown::No);
108 }
109 }
110 }
111
112 let combined = accepted
113 .iter()
114 .chain(&captured_dyn_filters)
115 .cloned()
116 .collect::<Vec<_>>();
117 if let Err(error) = validate_initial_registrations_for_pushdown(&combined) {
118 common_telemetry::warn!(error; "Remote dyn filters are not pushed down because initial registrations are invalid");
119 return RemoteDynFilterPushdown {
120 captured_dyn_filters: Vec::new(),
121 pushed_down: vec![PushedDown::No; pushed_down.len()],
122 };
123 }
124
125 RemoteDynFilterPushdown {
126 captured_dyn_filters,
127 pushed_down,
128 }
129}
130
131fn is_scalar_subquery_filter(filter: &Arc<dyn PhysicalExpr>) -> bool {
141 let mut has_scalar_subquery = false;
142 let mut supported = true;
143 let _ = filter.apply(|expr| {
144 if expr.is::<ScalarSubqueryExpr>() {
145 has_scalar_subquery = true;
146 } else if expr.is::<InListExpr>()
147 || (expr.children().is_empty() && !expr.is::<Column>() && !expr.is::<Literal>())
148 {
149 supported = false;
150 return Ok(TreeNodeRecursion::Stop);
151 }
152 Ok(TreeNodeRecursion::Continue)
153 });
154 has_scalar_subquery && supported
155}
156
157fn build_scalar_subquery_dyn_filter(
158 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
159 producer_local_ordinal: usize,
160 filter: Arc<dyn PhysicalExpr>,
161) -> Result<CapturedDynFilter> {
162 let mut columns = collect_columns(&filter).into_iter().collect::<Vec<_>>();
163 columns.sort_by_key(|column| column.index());
164 let children = columns
165 .into_iter()
166 .map(|column| Arc::new(column) as Arc<dyn PhysicalExpr>)
167 .collect();
168 let alive_dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(children, lit(true)));
169 let mut captured = build_captured_dyn_filter(
170 remote_dyn_filter_producer_id,
171 producer_local_ordinal,
172 alive_dyn_filter,
173 )?;
174 captured.scalar_subquery_filter = Some(filter);
175 Ok(captured)
176}
177
178pub(crate) fn resolve_scalar_subquery_dyn_filters(captured_dyn_filters: &[CapturedDynFilter]) {
185 for captured in captured_dyn_filters {
186 let Some(filter) = &captured.scalar_subquery_filter else {
187 continue;
188 };
189 let resolved = replace_scalar_subqueries(filter).unwrap_or_else(|error| {
190 common_telemetry::debug!(
191 "Scalar subquery filter {} is not forwarded to regions: {}",
192 filter,
193 error
194 );
195 lit(true)
196 });
197 if captured
198 .alive_dyn_filter
199 .current()
200 .is_ok_and(|current| current.as_ref() == resolved.as_ref())
201 {
202 continue;
203 }
204 if let Err(error) = captured.alive_dyn_filter.update(resolved) {
205 common_telemetry::warn!(error; "Failed to update scalar subquery remote dyn filter");
206 }
207 }
208}
209
210fn replace_scalar_subqueries(filter: &Arc<dyn PhysicalExpr>) -> Result<Arc<dyn PhysicalExpr>> {
211 let empty_batch =
212 arrow::record_batch::RecordBatch::new_empty(Arc::new(arrow_schema::Schema::empty()));
213 filter
214 .clone()
215 .transform_up(|expr| {
216 if !expr.is::<ScalarSubqueryExpr>() {
217 return Ok(Transformed::no(expr));
218 }
219 match expr.evaluate(&empty_batch)? {
221 ColumnarValue::Scalar(value) => Ok(Transformed::yes(lit(value))),
222 ColumnarValue::Array(_) => Err(datafusion_common::DataFusionError::Internal(
223 "scalar subquery evaluated to an array".to_string(),
224 )),
225 }
226 })
227 .map(|transformed| transformed.data)
228}
229
230fn downcast_dynamic_filter(
231 expr: Arc<dyn datafusion::physical_plan::PhysicalExpr>,
232) -> Option<Arc<DynamicFilterPhysicalExpr>> {
233 (expr as Arc<dyn Any + Send + Sync + 'static>)
234 .downcast::<DynamicFilterPhysicalExpr>()
235 .ok()
236}
237
238pub(crate) fn register_remote_dyn_filters(
239 registry: &QueryDynFilterRegistry,
240 captured_dyn_filters: &[CapturedDynFilter],
241) {
242 for captured_dyn_filter in captured_dyn_filters {
243 let _ = registry.register_remote_dyn_filter(
244 captured_dyn_filter.filter_id.clone(),
245 captured_dyn_filter.alive_dyn_filter.clone(),
246 );
247 }
248}
249
250pub(crate) fn register_dyn_filter_subscribers_for_region(
251 registry: &QueryDynFilterRegistry,
252 region_id: RegionId,
253 target: RegionQueryTarget,
254 captured_dyn_filters: &[CapturedDynFilter],
255) -> Vec<(FilterId, Subscriber)> {
256 let mut added = Vec::new();
257 for captured_dyn_filter in captured_dyn_filters {
258 let subscriber = Subscriber::new(region_id, target.clone());
259 let registration =
260 registry.register_subscriber(&captured_dyn_filter.filter_id, subscriber.clone());
261 match registration {
262 SubscriberRegistration::Added => {
263 added.push((captured_dyn_filter.filter_id.clone(), subscriber))
264 }
265 SubscriberRegistration::Duplicate => {}
266 SubscriberRegistration::MissingFilter => {
267 common_telemetry::warn!(
268 "Remote dynamic filter {} missing when registering subscriber for region {} at target {:?}",
269 captured_dyn_filter.filter_id,
270 region_id,
271 target
272 );
273 }
274 }
275 }
276 added
277}
278
279fn build_captured_dyn_filter(
280 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
281 producer_local_ordinal: usize,
282 alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
283) -> Result<CapturedDynFilter> {
284 let children = alive_dyn_filter
285 .children()
286 .into_iter()
287 .cloned()
288 .collect::<Vec<_>>();
289 let filter_id = build_remote_dyn_filter_id(
290 remote_dyn_filter_producer_id,
291 producer_local_ordinal,
292 &children,
293 )?;
294 let initial_registration =
295 InitialDynFilterReg::from_filter_id_and_children(filter_id.to_string(), &children)?;
296
297 Ok(CapturedDynFilter {
298 filter_id,
299 initial_registration: attach_initial_snapshot(initial_registration, &alive_dyn_filter),
300 alive_dyn_filter,
301 scalar_subquery_filter: None,
302 })
303}
304
305fn validate_initial_registrations_for_pushdown(
306 captured_dyn_filters: &[CapturedDynFilter],
307) -> std::result::Result<(), String> {
308 let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
309 regs.validate_default_bounds()?;
310 regs.to_extension_value()
311 .map_err(|error| error.to_string())?;
312 Ok(())
313}
314
315fn attach_initial_snapshot(
316 initial_registration: InitialDynFilterReg,
317 alive_dyn_filter: &DynamicFilterPhysicalExpr,
318) -> InitialDynFilterReg {
319 let Some(initial_snapshot) = initial_snapshot(alive_dyn_filter) else {
320 return initial_registration;
321 };
322
323 initial_registration.with_initial_snapshot(initial_snapshot)
324}
325
326fn initial_snapshot(
327 alive_dyn_filter: &DynamicFilterPhysicalExpr,
328) -> Option<InitialDynFilterSnapshot> {
329 let generation = alive_dyn_filter.snapshot_generation();
330 let current = match alive_dyn_filter.current() {
331 Ok(current) => current,
332 Err(error) => {
333 common_telemetry::warn!(error; "Failed to read remote dyn filter initial snapshot");
334 return None;
335 }
336 };
337
338 let payload = match DynFilterPayload::from_datafusion_expr(
339 ¤t,
340 REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
341 ) {
342 Ok(payload) => payload,
343 Err(error) => {
344 common_telemetry::warn!(error; "Failed to encode remote dyn filter initial snapshot");
345 return None;
346 }
347 };
348
349 let is_complete = false;
351 Some(InitialDynFilterSnapshot::new(
352 payload,
353 generation,
354 is_complete,
355 ))
356}
357
358fn build_initial_dyn_filter_regs_for_region(
359 captured_dyn_filters: &[CapturedDynFilter],
360) -> InitialDynFilterRegs {
361 InitialDynFilterRegs::new(
362 captured_dyn_filters
363 .iter()
364 .map(|captured| captured.initial_registration.clone())
365 .collect(),
366 )
367}
368
369pub(crate) fn query_context_with_initial_dyn_filter_regs(
370 query_ctx: &QueryContextRef,
371 region_id: RegionId,
372 captured_dyn_filters: &[CapturedDynFilter],
373) -> QueryContext {
374 let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
375 query_context_with_initial_dyn_filter_regs_value(query_ctx, region_id, ®s)
376}
377
378pub(crate) fn query_context_with_refreshed_initial_dyn_filter_regs(
379 query_ctx: &QueryContextRef,
380 _region_id: RegionId,
381 captured_dyn_filters: &[CapturedDynFilter],
382) -> QueryContext {
383 let refreshed = InitialDynFilterRegs::new(
384 captured_dyn_filters
385 .iter()
386 .map(|captured| {
387 attach_initial_snapshot(
388 captured.initial_registration.clone(),
389 &captured.alive_dyn_filter,
390 )
391 })
392 .collect(),
393 );
394 let serialized = match serialize_initial_dyn_filter_regs(&refreshed) {
395 Ok(serialized) => serialized,
396 Err(error) => {
397 common_telemetry::warn!(error; "Failed to refresh remote dynamic filter initial registrations; using optimization-time snapshots");
398 return query_context_with_initial_dyn_filter_regs(
399 query_ctx,
400 _region_id,
401 captured_dyn_filters,
402 );
403 }
404 };
405 query_context_with_serialized_initial_dyn_filter_regs(query_ctx, serialized)
406}
407
408fn query_context_with_initial_dyn_filter_regs_value(
409 query_ctx: &QueryContextRef,
410 region_id: RegionId,
411 regs: &InitialDynFilterRegs,
412) -> QueryContext {
413 let region_query_ctx = query_ctx.as_ref().clone();
414 if regs.is_empty() {
415 return region_query_ctx;
416 }
417
418 match serialize_initial_dyn_filter_regs(regs) {
419 Ok(serialized) => {
420 return query_context_with_serialized_initial_dyn_filter_regs(query_ctx, serialized);
421 }
422 Err(error) => {
423 common_telemetry::warn!(error; "Failed to serialize initial remote dyn filter registrations for region {}", region_id)
424 }
425 }
426
427 region_query_ctx
428}
429
430fn query_context_with_serialized_initial_dyn_filter_regs(
431 query_ctx: &QueryContextRef,
432 serialized: String,
433) -> QueryContext {
434 let mut region_query_ctx = query_ctx.as_ref().clone();
435 region_query_ctx.set_extension(
436 INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
437 serialized,
438 );
439 region_query_ctx
440}
441
442fn serialize_initial_dyn_filter_regs(
443 regs: &InitialDynFilterRegs,
444) -> std::result::Result<String, String> {
445 regs.validate_default_bounds()?;
446 regs.to_extension_value().map_err(|error| error.to_string())
447}
448
449#[cfg(test)]
450mod tests {
451 use std::fmt;
452 use std::hash::{Hash, Hasher};
453
454 use common_meta::peer::Peer;
455 use datafusion::execution::TaskContext;
456 use datafusion_common::ScalarValue;
457 use datafusion_expr::ColumnarValue;
458 use datafusion_expr::Operator;
459 use datafusion_expr::physical_planning_context::{ScalarSubqueryResults, SubqueryIndex};
460 use datafusion_physical_expr::expressions::BinaryExpr;
461 use session::query_id::QueryId;
462 use uuid::Uuid;
463
464 use super::*;
465 use crate::region_query::RegionQueryTarget;
466
467 #[derive(Debug)]
468 struct UnserializableExpr;
469
470 impl fmt::Display for UnserializableExpr {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 write!(f, "unserializable_expr")
473 }
474 }
475
476 impl Hash for UnserializableExpr {
477 fn hash<H: Hasher>(&self, state: &mut H) {
478 "unserializable_expr".hash(state);
479 }
480 }
481
482 impl PartialEq for UnserializableExpr {
483 fn eq(&self, _other: &Self) -> bool {
484 true
485 }
486 }
487
488 impl Eq for UnserializableExpr {}
489
490 impl datafusion_physical_expr::PhysicalExpr for UnserializableExpr {
491 fn data_type(
492 &self,
493 _input_schema: &arrow_schema::Schema,
494 ) -> datafusion_common::Result<arrow_schema::DataType> {
495 Ok(arrow_schema::DataType::Boolean)
496 }
497
498 fn nullable(
499 &self,
500 _input_schema: &arrow_schema::Schema,
501 ) -> datafusion_common::Result<bool> {
502 Ok(false)
503 }
504
505 fn evaluate(
506 &self,
507 _batch: &common_recordbatch::DfRecordBatch,
508 ) -> datafusion_common::Result<ColumnarValue> {
509 Ok(ColumnarValue::Scalar(ScalarValue::Boolean(Some(true))))
510 }
511
512 fn children(&self) -> Vec<&Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
513 Vec::new()
514 }
515
516 fn with_new_children(
517 self: Arc<Self>,
518 _children: Vec<Arc<dyn datafusion_physical_expr::PhysicalExpr>>,
519 ) -> datafusion_common::Result<Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
520 Ok(self)
521 }
522
523 fn fmt_sql(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524 write!(f, "{self}")
525 }
526 }
527
528 fn test_query_id(value: u128) -> QueryId {
529 QueryId::from(Uuid::from_u128(value))
530 }
531
532 fn test_remote_dyn_filter_producer_id(value: u64) -> RemoteDynFilterProducerId {
533 RemoteDynFilterProducerId::new(value)
534 }
535
536 fn test_target(id: u64) -> RegionQueryTarget {
537 RegionQueryTarget::new(Peer {
538 id,
539 addr: format!("127.0.0.1:{id}"),
540 })
541 }
542
543 fn test_captured_dyn_filter(
544 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
545 producer_local_ordinal: usize,
546 column_name: &str,
547 column_index: usize,
548 ) -> CapturedDynFilter {
549 build_captured_dyn_filter(
550 remote_dyn_filter_producer_id,
551 producer_local_ordinal,
552 Arc::new(DynamicFilterPhysicalExpr::new(
553 vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
554 lit(true) as _,
555 )),
556 )
557 .unwrap()
558 }
559
560 fn test_dyn_filter_with_snapshot_payload(
561 column_name: &str,
562 column_index: usize,
563 payload_bytes: usize,
564 ) -> Arc<DynamicFilterPhysicalExpr> {
565 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
566 vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
567 lit(true) as _,
568 ));
569 dyn_filter
570 .update(lit(ScalarValue::Utf8(Some("x".repeat(payload_bytes)))) as _)
571 .unwrap();
572 dyn_filter
573 }
574
575 fn refreshed_regs(captured: &[CapturedDynFilter]) -> InitialDynFilterRegs {
576 let query_ctx = QueryContext::arc();
577 let region_query_ctx = query_context_with_refreshed_initial_dyn_filter_regs(
578 &query_ctx,
579 RegionId::new(1024, 7),
580 captured,
581 );
582 InitialDynFilterRegs::from_extension_value(
583 region_query_ctx
584 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
585 .unwrap(),
586 )
587 .unwrap()
588 }
589
590 fn decode_snapshot(snapshot: &InitialDynFilterSnapshot, column_name: &str) -> String {
591 snapshot
592 .payload
593 .decode_datafusion_expr(
594 &TaskContext::default(),
595 &arrow_schema::Schema::new(vec![arrow_schema::Field::new(
596 column_name,
597 arrow_schema::DataType::Utf8,
598 false,
599 )]),
600 REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
601 )
602 .unwrap()
603 .to_string()
604 }
605
606 fn pushed_down(pushdown: &RemoteDynFilterPushdown) -> Vec<bool> {
607 pushdown
608 .pushed_down
609 .iter()
610 .map(|pushed_down| matches!(pushed_down, PushedDown::Yes))
611 .collect()
612 }
613
614 fn host_eq_scalar_subquery(results: &ScalarSubqueryResults) -> Arc<dyn PhysicalExpr> {
615 Arc::new(BinaryExpr::new(
616 Arc::new(Column::new("host", 0)),
617 Operator::Eq,
618 Arc::new(ScalarSubqueryExpr::new(
619 arrow_schema::DataType::Utf8,
620 true,
621 SubqueryIndex::new(0),
622 results.clone(),
623 )),
624 ))
625 }
626
627 #[test]
628 fn scalar_subquery_filter_is_captured_but_left_to_parent() {
629 let results = ScalarSubqueryResults::new(1);
630 let parent_filters = vec![
631 host_eq_scalar_subquery(&results),
632 Arc::new(BinaryExpr::new(
633 Arc::new(Column::new("host", 0)),
634 Operator::Eq,
635 lit("a"),
636 )) as Arc<dyn PhysicalExpr>,
637 ];
638
639 let pushdown = capture_remote_dyn_filters_for_pushdown(
640 test_remote_dyn_filter_producer_id(42),
641 0,
642 &[],
643 parent_filters,
644 );
645
646 assert_eq!(pushed_down(&pushdown), vec![false, false]);
647 assert_eq!(pushdown.captured_dyn_filters.len(), 1);
648 assert_eq!(
649 pushdown.captured_dyn_filters[0]
650 .filter_id
651 .producer_ordinal(),
652 0
653 );
654 }
655
656 #[test]
657 fn scalar_subquery_filter_with_in_list_is_left_to_parent() {
658 let results = ScalarSubqueryResults::new(1);
659 let schema = arrow_schema::Schema::new(vec![arrow_schema::Field::new(
660 "host",
661 arrow_schema::DataType::Utf8,
662 true,
663 )]);
664 let host_in_list = datafusion_physical_expr::expressions::in_list(
665 Arc::new(Column::new("host", 0)),
666 vec![lit("a"), lit("b")],
667 &false,
668 &schema,
669 )
670 .unwrap();
671 let filter = Arc::new(BinaryExpr::new(
673 host_in_list,
674 Operator::Eq,
675 Arc::new(ScalarSubqueryExpr::new(
676 arrow_schema::DataType::Boolean,
677 true,
678 SubqueryIndex::new(0),
679 results,
680 )),
681 )) as Arc<dyn PhysicalExpr>;
682
683 let pushdown = capture_remote_dyn_filters_for_pushdown(
684 test_remote_dyn_filter_producer_id(42),
685 0,
686 &[],
687 vec![filter],
688 );
689
690 assert_eq!(pushed_down(&pushdown), vec![false]);
691 assert!(pushdown.captured_dyn_filters.is_empty());
692 }
693
694 #[test]
695 fn scalar_subquery_dyn_filter_follows_subquery_results() {
696 let results = ScalarSubqueryResults::new(1);
697 let captured = capture_remote_dyn_filters_for_pushdown(
698 test_remote_dyn_filter_producer_id(42),
699 0,
700 &[],
701 vec![host_eq_scalar_subquery(&results)],
702 )
703 .captured_dyn_filters;
704 let snapshot = |captured: &[CapturedDynFilter]| {
705 decode_snapshot(
706 refreshed_regs(captured).regs[0]
707 .initial_snapshot
708 .as_ref()
709 .unwrap(),
710 "host",
711 )
712 };
713
714 resolve_scalar_subquery_dyn_filters(&captured);
716 assert_eq!(snapshot(&captured), "true");
717
718 results
719 .set(
720 SubqueryIndex::new(0),
721 ScalarValue::Utf8(Some("a".to_string())),
722 )
723 .unwrap();
724 resolve_scalar_subquery_dyn_filters(&captured);
725 assert_eq!(snapshot(&captured), "host@0 = a");
726
727 results.clear();
729 resolve_scalar_subquery_dyn_filters(&captured);
730 assert_eq!(snapshot(&captured), "true");
731 }
732
733 #[test]
734 fn capture_remote_dyn_filters_for_pushdown_preserves_parent_filter_ordinals() {
735 let parent_filters = vec![
736 Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
737 Arc::new(DynamicFilterPhysicalExpr::new(
738 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
739 lit(true) as _,
740 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
741 Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
742 Arc::new(DynamicFilterPhysicalExpr::new(
743 vec![Arc::new(Column::new("pod", 3)) as Arc<_>],
744 lit(true) as _,
745 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
746 ];
747
748 let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
749 let captured = capture_remote_dyn_filters_for_pushdown(
750 remote_dyn_filter_producer_id,
751 0,
752 &[],
753 parent_filters,
754 )
755 .captured_dyn_filters;
756
757 assert_eq!(captured.len(), 2);
758 assert_eq!(
759 captured[0].filter_id.remote_dyn_filter_producer_id(),
760 remote_dyn_filter_producer_id
761 );
762 assert_eq!(
763 captured[1].filter_id.remote_dyn_filter_producer_id(),
764 remote_dyn_filter_producer_id
765 );
766 assert_eq!(captured[0].filter_id.producer_ordinal(), 1);
767 assert_eq!(captured[1].filter_id.producer_ordinal(), 3);
768 }
769
770 #[test]
771 fn capture_remote_dyn_filters_for_pushdown_marks_only_valid_initial_regs() {
772 let parent_filters = vec![
773 Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
774 Arc::new(DynamicFilterPhysicalExpr::new(
775 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
776 lit(true) as _,
777 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
778 Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
779 ];
780
781 let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
782 let pushdown = capture_remote_dyn_filters_for_pushdown(
783 remote_dyn_filter_producer_id,
784 0,
785 &[],
786 parent_filters,
787 );
788
789 assert_eq!(pushed_down(&pushdown), vec![false, true, false]);
790 assert_eq!(pushdown.captured_dyn_filters.len(), 1);
791 assert_eq!(
792 pushdown.captured_dyn_filters[0]
793 .filter_id
794 .remote_dyn_filter_producer_id(),
795 remote_dyn_filter_producer_id
796 );
797 assert_eq!(
798 pushdown.captured_dyn_filters[0]
799 .filter_id
800 .producer_ordinal(),
801 1
802 );
803 assert!(
804 pushdown.captured_dyn_filters[0]
805 .initial_registration
806 .initial_snapshot
807 .is_some()
808 );
809 }
810
811 #[test]
812 fn capture_remote_dyn_filters_for_pushdown_rejects_unencodable_registration() {
813 let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
814 vec![Arc::new(UnserializableExpr) as Arc<_>],
815 lit(true) as _,
816 ))
817 as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
818
819 let pushdown = capture_remote_dyn_filters_for_pushdown(
820 test_remote_dyn_filter_producer_id(42),
821 0,
822 &[],
823 parent_filters,
824 );
825
826 assert_eq!(pushed_down(&pushdown), vec![false]);
827 assert!(pushdown.captured_dyn_filters.is_empty());
828 }
829
830 #[test]
831 fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot() {
832 let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
833 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
834 lit(true) as _,
835 ))
836 as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
837
838 let pushdown = capture_remote_dyn_filters_for_pushdown(
839 test_remote_dyn_filter_producer_id(42),
840 0,
841 &[],
842 parent_filters,
843 );
844
845 assert_eq!(pushed_down(&pushdown), vec![true]);
846 assert!(
847 pushdown.captured_dyn_filters[0]
848 .initial_registration
849 .initial_snapshot
850 .is_some()
851 );
852 }
853
854 #[test]
855 fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot_after_update() {
856 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
857 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
858 lit(true) as _,
859 ));
860 dyn_filter.update(lit(false) as _).unwrap();
861 let parent_filters = vec![dyn_filter as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
862
863 let pushdown = capture_remote_dyn_filters_for_pushdown(
864 test_remote_dyn_filter_producer_id(42),
865 0,
866 &[],
867 parent_filters,
868 );
869
870 assert_eq!(pushed_down(&pushdown), vec![true]);
871 let snapshot = pushdown.captured_dyn_filters[0]
872 .initial_registration
873 .initial_snapshot
874 .as_ref()
875 .unwrap();
876 assert_eq!(snapshot.generation, 2);
877 assert!(!snapshot.is_complete);
878 assert!(matches!(
879 snapshot.payload,
880 DynFilterPayload::Datafusion(ref bytes) if !bytes.is_empty()
881 ));
882 }
883
884 #[test]
885 fn capture_remote_dyn_filters_for_pushdown_rejects_oversized_snapshots() {
886 let oversized_total_snapshot_bytes = REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES * 3 / 5;
887 let parent_filters = vec![
888 test_dyn_filter_with_snapshot_payload("host", 0, oversized_total_snapshot_bytes)
889 as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
890 test_dyn_filter_with_snapshot_payload("pod", 1, oversized_total_snapshot_bytes)
891 as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
892 ];
893
894 let pushdown = capture_remote_dyn_filters_for_pushdown(
895 test_remote_dyn_filter_producer_id(42),
896 0,
897 &[],
898 parent_filters,
899 );
900
901 assert_eq!(pushed_down(&pushdown), vec![false, false]);
902 assert!(pushdown.captured_dyn_filters.is_empty());
903 }
904
905 #[test]
906 fn capture_remote_dyn_filters_for_pushdown_keeps_accepted_filters_within_budget() {
907 const MAX_INITIAL_REGS: usize = 64;
908
909 let accepted = capture_remote_dyn_filters_for_pushdown(
910 test_remote_dyn_filter_producer_id(42),
911 0,
912 &[],
913 (0..MAX_INITIAL_REGS)
914 .map(|ordinal| {
915 test_dyn_filter_with_snapshot_payload(&format!("host_{ordinal}"), ordinal, 1)
916 as Arc<dyn PhysicalExpr>
917 })
918 .collect(),
919 )
920 .captured_dyn_filters;
921 assert_eq!(accepted.len(), MAX_INITIAL_REGS);
922
923 let results = ScalarSubqueryResults::new(1);
924 let pushdown = capture_remote_dyn_filters_for_pushdown(
925 test_remote_dyn_filter_producer_id(42),
926 1 << 31,
927 &accepted,
928 vec![host_eq_scalar_subquery(&results)],
929 );
930
931 assert_eq!(pushed_down(&pushdown), vec![false]);
932 assert!(pushdown.captured_dyn_filters.is_empty());
933 }
934
935 #[test]
936 fn capture_remote_dyn_filters_for_pushdown_rejects_too_many_regs_with_snapshots() {
937 const TOO_MANY_INITIAL_REGS: usize = 65;
938
939 let parent_filters = (0..TOO_MANY_INITIAL_REGS)
940 .map(|ordinal| {
941 test_dyn_filter_with_snapshot_payload(&format!("host_{ordinal}"), ordinal, 1)
942 as Arc<dyn datafusion::physical_plan::PhysicalExpr>
943 })
944 .collect::<Vec<_>>();
945
946 let pushdown = capture_remote_dyn_filters_for_pushdown(
947 test_remote_dyn_filter_producer_id(42),
948 0,
949 &[],
950 parent_filters,
951 );
952
953 assert!(pushdown.captured_dyn_filters.is_empty());
954 assert_eq!(pushed_down(&pushdown), vec![false; TOO_MANY_INITIAL_REGS]);
955 }
956
957 #[test]
958 fn capture_remote_dyn_filters_for_pushdown_rejects_regs_exceeding_bounds() {
959 const TOO_MANY_INITIAL_REGS: usize = 65;
960
961 let parent_filters = (0..TOO_MANY_INITIAL_REGS)
962 .map(|_| {
963 Arc::new(DynamicFilterPhysicalExpr::new(
964 vec![Arc::new(Column::new("host", 0)) as Arc<_>],
965 lit(true) as _,
966 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>
967 })
968 .collect::<Vec<_>>();
969
970 let pushdown = capture_remote_dyn_filters_for_pushdown(
971 test_remote_dyn_filter_producer_id(42),
972 0,
973 &[],
974 parent_filters,
975 );
976
977 assert!(pushdown.captured_dyn_filters.is_empty());
978 assert_eq!(pushed_down(&pushdown), vec![false; TOO_MANY_INITIAL_REGS]);
979 }
980
981 #[test]
982 fn register_dyn_filter_subscribers_for_region_reuses_existing_entry() {
983 let registry = QueryDynFilterRegistry::new(test_query_id(1));
984 let captured_dyn_filters = vec![test_captured_dyn_filter(
985 test_remote_dyn_filter_producer_id(42),
986 2,
987 "host",
988 0,
989 )];
990 let first_region_id = RegionId::new(1024, 7);
991 let second_region_id = RegionId::new(1024, 8);
992
993 register_remote_dyn_filters(®istry, &captured_dyn_filters);
994 register_dyn_filter_subscribers_for_region(
995 ®istry,
996 first_region_id,
997 test_target(1),
998 &captured_dyn_filters,
999 );
1000 register_dyn_filter_subscribers_for_region(
1001 ®istry,
1002 second_region_id,
1003 test_target(2),
1004 &captured_dyn_filters,
1005 );
1006
1007 assert_eq!(registry.entry_count(), 1);
1008 let entry = registry.entries().pop().unwrap();
1009 assert_eq!(
1010 entry.filter_id().remote_dyn_filter_producer_id(),
1011 test_remote_dyn_filter_producer_id(42)
1012 );
1013 assert_eq!(entry.filter_id().producer_ordinal(), 2);
1014 let subscribers = entry.subscribers();
1015 assert_eq!(subscribers.len(), 2);
1016 assert!(
1017 subscribers
1018 .iter()
1019 .any(|subscriber| subscriber.region_id() == first_region_id)
1020 );
1021 assert!(
1022 subscribers
1023 .iter()
1024 .any(|subscriber| subscriber.region_id() == second_region_id)
1025 );
1026 }
1027
1028 #[test]
1029 fn register_remote_dyn_filters_keeps_independent_producer_ids_distinct() {
1030 let registry = QueryDynFilterRegistry::new(test_query_id(1));
1031 let make_filter = |remote_dyn_filter_producer_id| {
1032 test_captured_dyn_filter(remote_dyn_filter_producer_id, 2, "host", 0)
1033 };
1034
1035 register_remote_dyn_filters(
1036 ®istry,
1037 &[make_filter(test_remote_dyn_filter_producer_id(42))],
1038 );
1039 register_remote_dyn_filters(
1040 ®istry,
1041 &[make_filter(test_remote_dyn_filter_producer_id(43))],
1042 );
1043
1044 assert_eq!(registry.entry_count(), 2);
1045 }
1046
1047 #[test]
1048 fn query_context_includes_region_initial_dyn_filter_regs() {
1049 let captured_dyn_filters = vec![test_captured_dyn_filter(
1050 test_remote_dyn_filter_producer_id(42),
1051 2,
1052 "host",
1053 0,
1054 )];
1055 let region_id = RegionId::new(1024, 7);
1056 let query_ctx = QueryContext::arc();
1057
1058 let region_query_ctx = query_context_with_initial_dyn_filter_regs(
1059 &query_ctx,
1060 region_id,
1061 &captured_dyn_filters,
1062 );
1063 let extension = region_query_ctx
1064 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
1065 .unwrap();
1066 let regs = InitialDynFilterRegs::from_extension_value(extension).unwrap();
1067 let decoded_children = regs.regs[0]
1068 .decode_children(
1069 &TaskContext::default(),
1070 &arrow_schema::Schema::new(vec![arrow_schema::Field::new(
1071 "host",
1072 arrow_schema::DataType::Utf8,
1073 false,
1074 )]),
1075 1024,
1076 )
1077 .unwrap();
1078 assert_eq!(regs.regs.len(), 1);
1079 assert_eq!(
1080 regs.regs[0].filter_id,
1081 captured_dyn_filters[0].filter_id.to_string()
1082 );
1083 assert_eq!(decoded_children.len(), 1);
1084 assert!(decoded_children[0].is::<Column>());
1085 }
1086
1087 #[test]
1088 fn refreshed_initial_regs_use_live_filter_snapshot_without_mutating_capture() {
1089 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
1090 vec![Arc::new(Column::new("host", 0)) as Arc<_>],
1091 lit(true) as _,
1092 ));
1093 let captured = vec![
1094 build_captured_dyn_filter(
1095 test_remote_dyn_filter_producer_id(42),
1096 0,
1097 dyn_filter.clone(),
1098 )
1099 .unwrap(),
1100 ];
1101 let original_generation = captured[0]
1102 .initial_registration
1103 .initial_snapshot
1104 .as_ref()
1105 .unwrap()
1106 .generation;
1107 dyn_filter.update(lit(false) as _).unwrap();
1108 dyn_filter.mark_complete();
1109
1110 let regs = refreshed_regs(&captured);
1111
1112 let snapshot = regs.regs[0].initial_snapshot.as_ref().unwrap();
1113 assert_eq!(snapshot.generation, 2);
1114 assert!(!snapshot.is_complete);
1115 assert_ne!(decode_snapshot(snapshot, "host"), "true");
1116 assert_eq!(
1117 captured[0]
1118 .initial_registration
1119 .initial_snapshot
1120 .as_ref()
1121 .unwrap()
1122 .generation,
1123 original_generation
1124 );
1125 }
1126
1127 #[test]
1128 fn refresh_keeps_old_snapshot_when_one_live_filter_cannot_encode() {
1129 let good = Arc::new(DynamicFilterPhysicalExpr::new(
1130 vec![Arc::new(Column::new("good", 0)) as Arc<_>],
1131 lit(true) as _,
1132 ));
1133 let bad = Arc::new(DynamicFilterPhysicalExpr::new(
1134 vec![Arc::new(Column::new("bad", 0)) as Arc<_>],
1135 lit(true) as _,
1136 ));
1137 let captured = vec![
1138 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 0, good.clone())
1139 .unwrap(),
1140 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 1, bad.clone())
1141 .unwrap(),
1142 ];
1143 let old_bad_generation = captured[1]
1144 .initial_registration
1145 .initial_snapshot
1146 .as_ref()
1147 .unwrap()
1148 .generation;
1149 good.update(lit(false) as _).unwrap();
1150 bad.update(Arc::new(UnserializableExpr) as _).unwrap();
1151
1152 let regs = refreshed_regs(&captured);
1153 assert_eq!(
1154 regs.regs[0].initial_snapshot.as_ref().unwrap().generation,
1155 2
1156 );
1157 assert_eq!(
1158 regs.regs[1].initial_snapshot.as_ref().unwrap().generation,
1159 old_bad_generation
1160 );
1161 }
1162
1163 #[test]
1164 fn refresh_aggregate_overflow_falls_back_to_original_snapshots() {
1165 let payload_bytes = REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES * 3 / 5;
1166 let first = test_dyn_filter_with_snapshot_payload("first", 0, 1);
1167 let second = test_dyn_filter_with_snapshot_payload("second", 0, 1);
1168 let captured = vec![
1169 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 0, first.clone())
1170 .unwrap(),
1171 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 1, second.clone())
1172 .unwrap(),
1173 ];
1174 let original = captured
1175 .iter()
1176 .map(|captured| {
1177 captured
1178 .initial_registration
1179 .initial_snapshot
1180 .clone()
1181 .unwrap()
1182 })
1183 .collect::<Vec<_>>();
1184 first
1185 .update(lit(ScalarValue::Utf8(Some("x".repeat(payload_bytes)))) as _)
1186 .unwrap();
1187 second
1188 .update(lit(ScalarValue::Utf8(Some("y".repeat(payload_bytes)))) as _)
1189 .unwrap();
1190
1191 let regs = refreshed_regs(&captured);
1192 for (refreshed, original) in regs.regs.iter().zip(original) {
1193 let refreshed = refreshed.initial_snapshot.as_ref().unwrap();
1194 assert_eq!(refreshed.generation, original.generation);
1195 assert_eq!(refreshed.payload, original.payload);
1196 }
1197 }
1198
1199 #[test]
1200 fn query_context_drops_initial_regs_when_duplicate_filter_ids_exceed_bounds() {
1201 let captured_dyn_filters = vec![
1202 test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
1203 test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
1204 ];
1205 let region_id = RegionId::new(1024, 7);
1206 let query_ctx = QueryContext::arc();
1207
1208 let region_query_ctx = query_context_with_initial_dyn_filter_regs(
1209 &query_ctx,
1210 region_id,
1211 &captured_dyn_filters,
1212 );
1213
1214 assert!(
1215 region_query_ctx
1216 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
1217 .is_none()
1218 );
1219 }
1220}