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_common::Result;
23use datafusion_physical_expr::PhysicalExpr;
24use datafusion_physical_expr::expressions::DynamicFilterPhysicalExpr;
25use session::context::{QueryContext, QueryContextRef};
26use store_api::storage::RegionId;
27
28use crate::dist_plan::filter_id::build_remote_dyn_filter_id;
29use crate::dist_plan::{
30 FilterId, QueryDynFilterRegistry, RemoteDynFilterProducerId, Subscriber, SubscriberRegistration,
31};
32use crate::region_query::RegionQueryTarget;
33
34#[derive(Debug, Clone)]
35pub(crate) struct CapturedDynFilter {
36 filter_id: FilterId,
37 initial_registration: InitialDynFilterReg,
38 pub(crate) alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
39}
40
41#[derive(Debug, Clone)]
42pub(crate) struct RemoteDynFilterPushdown {
43 pub(crate) captured_dyn_filters: Vec<CapturedDynFilter>,
44 pub(crate) pushed_down: Vec<bool>,
46}
47
48pub(crate) fn capture_remote_dyn_filters_for_pushdown(
49 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
50 parent_filters: Vec<Arc<dyn datafusion::physical_plan::PhysicalExpr>>,
51) -> RemoteDynFilterPushdown {
52 let mut pushed_down = Vec::with_capacity(parent_filters.len());
53 let mut captured_dyn_filters = Vec::new();
54
55 for (producer_local_ordinal, filter) in parent_filters.into_iter().enumerate() {
56 let Some(alive_dyn_filter) = downcast_dynamic_filter(filter) else {
57 pushed_down.push(false);
58 continue;
59 };
60
61 match build_captured_dyn_filter(
62 remote_dyn_filter_producer_id,
63 producer_local_ordinal,
64 alive_dyn_filter,
65 ) {
66 Ok(captured_dyn_filter) => {
67 pushed_down.push(true);
68 captured_dyn_filters.push(captured_dyn_filter);
69 }
70 Err(error) => {
71 common_telemetry::warn!(error; "Remote dyn filter is not pushed down because initial registration cannot be built");
72 pushed_down.push(false);
73 }
74 }
75 }
76
77 if let Err(error) = validate_initial_registrations_for_pushdown(&captured_dyn_filters) {
78 common_telemetry::warn!(error; "Remote dyn filters are not pushed down because initial registrations are invalid");
79 return RemoteDynFilterPushdown {
80 captured_dyn_filters: Vec::new(),
81 pushed_down: vec![false; pushed_down.len()],
82 };
83 }
84
85 RemoteDynFilterPushdown {
86 captured_dyn_filters,
87 pushed_down,
88 }
89}
90
91fn downcast_dynamic_filter(
92 expr: Arc<dyn datafusion::physical_plan::PhysicalExpr>,
93) -> Option<Arc<DynamicFilterPhysicalExpr>> {
94 (expr as Arc<dyn Any + Send + Sync + 'static>)
95 .downcast::<DynamicFilterPhysicalExpr>()
96 .ok()
97}
98
99pub(crate) fn register_remote_dyn_filters(
100 registry: &QueryDynFilterRegistry,
101 captured_dyn_filters: &[CapturedDynFilter],
102) {
103 for captured_dyn_filter in captured_dyn_filters {
104 let _ = registry.register_remote_dyn_filter(
105 captured_dyn_filter.filter_id.clone(),
106 captured_dyn_filter.alive_dyn_filter.clone(),
107 );
108 }
109}
110
111pub(crate) fn register_dyn_filter_subscribers_for_region(
112 registry: &QueryDynFilterRegistry,
113 region_id: RegionId,
114 target: RegionQueryTarget,
115 captured_dyn_filters: &[CapturedDynFilter],
116) -> Vec<(FilterId, Subscriber)> {
117 let mut added = Vec::new();
118 for captured_dyn_filter in captured_dyn_filters {
119 let subscriber = Subscriber::new(region_id, target.clone());
120 let registration =
121 registry.register_subscriber(&captured_dyn_filter.filter_id, subscriber.clone());
122 match registration {
123 SubscriberRegistration::Added => {
124 added.push((captured_dyn_filter.filter_id.clone(), subscriber))
125 }
126 SubscriberRegistration::Duplicate => {}
127 SubscriberRegistration::MissingFilter => {
128 common_telemetry::warn!(
129 "Remote dynamic filter {} missing when registering subscriber for region {} at target {:?}",
130 captured_dyn_filter.filter_id,
131 region_id,
132 target
133 );
134 }
135 }
136 }
137 added
138}
139
140fn build_captured_dyn_filter(
141 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
142 producer_local_ordinal: usize,
143 alive_dyn_filter: Arc<DynamicFilterPhysicalExpr>,
144) -> Result<CapturedDynFilter> {
145 let children = alive_dyn_filter
146 .children()
147 .into_iter()
148 .cloned()
149 .collect::<Vec<_>>();
150 let filter_id = build_remote_dyn_filter_id(
151 remote_dyn_filter_producer_id,
152 producer_local_ordinal,
153 &children,
154 )?;
155 let initial_registration =
156 InitialDynFilterReg::from_filter_id_and_children(filter_id.to_string(), &children)?;
157
158 Ok(CapturedDynFilter {
159 filter_id,
160 initial_registration: attach_initial_snapshot(initial_registration, &alive_dyn_filter),
161 alive_dyn_filter,
162 })
163}
164
165fn validate_initial_registrations_for_pushdown(
166 captured_dyn_filters: &[CapturedDynFilter],
167) -> std::result::Result<(), String> {
168 let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
169 regs.validate_default_bounds()?;
170 regs.to_extension_value()
171 .map_err(|error| error.to_string())?;
172 Ok(())
173}
174
175fn attach_initial_snapshot(
176 initial_registration: InitialDynFilterReg,
177 alive_dyn_filter: &DynamicFilterPhysicalExpr,
178) -> InitialDynFilterReg {
179 let Some(initial_snapshot) = initial_snapshot(alive_dyn_filter) else {
180 return initial_registration;
181 };
182
183 initial_registration.with_initial_snapshot(initial_snapshot)
184}
185
186fn initial_snapshot(
187 alive_dyn_filter: &DynamicFilterPhysicalExpr,
188) -> Option<InitialDynFilterSnapshot> {
189 let generation = alive_dyn_filter.snapshot_generation();
190 let current = match alive_dyn_filter.current() {
191 Ok(current) => current,
192 Err(error) => {
193 common_telemetry::warn!(error; "Failed to read remote dyn filter initial snapshot");
194 return None;
195 }
196 };
197
198 let payload = match DynFilterPayload::from_datafusion_expr(
199 ¤t,
200 REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
201 ) {
202 Ok(payload) => payload,
203 Err(error) => {
204 common_telemetry::warn!(error; "Failed to encode remote dyn filter initial snapshot");
205 return None;
206 }
207 };
208
209 let is_complete = false;
211 Some(InitialDynFilterSnapshot::new(
212 payload,
213 generation,
214 is_complete,
215 ))
216}
217
218fn build_initial_dyn_filter_regs_for_region(
219 captured_dyn_filters: &[CapturedDynFilter],
220) -> InitialDynFilterRegs {
221 InitialDynFilterRegs::new(
222 captured_dyn_filters
223 .iter()
224 .map(|captured| captured.initial_registration.clone())
225 .collect(),
226 )
227}
228
229pub(crate) fn query_context_with_initial_dyn_filter_regs(
230 query_ctx: &QueryContextRef,
231 region_id: RegionId,
232 captured_dyn_filters: &[CapturedDynFilter],
233) -> QueryContext {
234 let regs = build_initial_dyn_filter_regs_for_region(captured_dyn_filters);
235 query_context_with_initial_dyn_filter_regs_value(query_ctx, region_id, ®s)
236}
237
238pub(crate) fn query_context_with_refreshed_initial_dyn_filter_regs(
239 query_ctx: &QueryContextRef,
240 _region_id: RegionId,
241 captured_dyn_filters: &[CapturedDynFilter],
242) -> QueryContext {
243 let refreshed = InitialDynFilterRegs::new(
244 captured_dyn_filters
245 .iter()
246 .map(|captured| {
247 attach_initial_snapshot(
248 captured.initial_registration.clone(),
249 &captured.alive_dyn_filter,
250 )
251 })
252 .collect(),
253 );
254 let serialized = match serialize_initial_dyn_filter_regs(&refreshed) {
255 Ok(serialized) => serialized,
256 Err(error) => {
257 common_telemetry::warn!(error; "Failed to refresh remote dynamic filter initial registrations; using optimization-time snapshots");
258 return query_context_with_initial_dyn_filter_regs(
259 query_ctx,
260 _region_id,
261 captured_dyn_filters,
262 );
263 }
264 };
265 query_context_with_serialized_initial_dyn_filter_regs(query_ctx, serialized)
266}
267
268fn query_context_with_initial_dyn_filter_regs_value(
269 query_ctx: &QueryContextRef,
270 region_id: RegionId,
271 regs: &InitialDynFilterRegs,
272) -> QueryContext {
273 let region_query_ctx = query_ctx.as_ref().clone();
274 if regs.is_empty() {
275 return region_query_ctx;
276 }
277
278 match serialize_initial_dyn_filter_regs(regs) {
279 Ok(serialized) => {
280 return query_context_with_serialized_initial_dyn_filter_regs(query_ctx, serialized);
281 }
282 Err(error) => {
283 common_telemetry::warn!(error; "Failed to serialize initial remote dyn filter registrations for region {}", region_id)
284 }
285 }
286
287 region_query_ctx
288}
289
290fn query_context_with_serialized_initial_dyn_filter_regs(
291 query_ctx: &QueryContextRef,
292 serialized: String,
293) -> QueryContext {
294 let mut region_query_ctx = query_ctx.as_ref().clone();
295 region_query_ctx.set_extension(
296 INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
297 serialized,
298 );
299 region_query_ctx
300}
301
302fn serialize_initial_dyn_filter_regs(
303 regs: &InitialDynFilterRegs,
304) -> std::result::Result<String, String> {
305 regs.validate_default_bounds()?;
306 regs.to_extension_value().map_err(|error| error.to_string())
307}
308
309#[cfg(test)]
310mod tests {
311 use std::fmt;
312 use std::hash::{Hash, Hasher};
313
314 use common_meta::peer::Peer;
315 use datafusion::execution::TaskContext;
316 use datafusion_common::ScalarValue;
317 use datafusion_expr::ColumnarValue;
318 use datafusion_physical_expr::expressions::{Column, lit};
319 use session::query_id::QueryId;
320 use uuid::Uuid;
321
322 use super::*;
323 use crate::region_query::RegionQueryTarget;
324
325 #[derive(Debug)]
326 struct UnserializableExpr;
327
328 impl fmt::Display for UnserializableExpr {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 write!(f, "unserializable_expr")
331 }
332 }
333
334 impl Hash for UnserializableExpr {
335 fn hash<H: Hasher>(&self, state: &mut H) {
336 "unserializable_expr".hash(state);
337 }
338 }
339
340 impl PartialEq for UnserializableExpr {
341 fn eq(&self, _other: &Self) -> bool {
342 true
343 }
344 }
345
346 impl Eq for UnserializableExpr {}
347
348 impl datafusion_physical_expr::PhysicalExpr for UnserializableExpr {
349 fn as_any(&self) -> &dyn Any {
350 self
351 }
352
353 fn data_type(
354 &self,
355 _input_schema: &arrow_schema::Schema,
356 ) -> datafusion_common::Result<arrow_schema::DataType> {
357 Ok(arrow_schema::DataType::Boolean)
358 }
359
360 fn nullable(
361 &self,
362 _input_schema: &arrow_schema::Schema,
363 ) -> datafusion_common::Result<bool> {
364 Ok(false)
365 }
366
367 fn evaluate(
368 &self,
369 _batch: &common_recordbatch::DfRecordBatch,
370 ) -> datafusion_common::Result<ColumnarValue> {
371 Ok(ColumnarValue::Scalar(ScalarValue::Boolean(Some(true))))
372 }
373
374 fn children(&self) -> Vec<&Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
375 Vec::new()
376 }
377
378 fn with_new_children(
379 self: Arc<Self>,
380 _children: Vec<Arc<dyn datafusion_physical_expr::PhysicalExpr>>,
381 ) -> datafusion_common::Result<Arc<dyn datafusion_physical_expr::PhysicalExpr>> {
382 Ok(self)
383 }
384
385 fn fmt_sql(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 write!(f, "{self}")
387 }
388 }
389
390 fn test_query_id(value: u128) -> QueryId {
391 QueryId::from(Uuid::from_u128(value))
392 }
393
394 fn test_remote_dyn_filter_producer_id(value: u64) -> RemoteDynFilterProducerId {
395 RemoteDynFilterProducerId::new(value)
396 }
397
398 fn test_target(id: u64) -> RegionQueryTarget {
399 RegionQueryTarget::new(Peer {
400 id,
401 addr: format!("127.0.0.1:{id}"),
402 })
403 }
404
405 fn test_captured_dyn_filter(
406 remote_dyn_filter_producer_id: RemoteDynFilterProducerId,
407 producer_local_ordinal: usize,
408 column_name: &str,
409 column_index: usize,
410 ) -> CapturedDynFilter {
411 build_captured_dyn_filter(
412 remote_dyn_filter_producer_id,
413 producer_local_ordinal,
414 Arc::new(DynamicFilterPhysicalExpr::new(
415 vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
416 lit(true) as _,
417 )),
418 )
419 .unwrap()
420 }
421
422 fn test_dyn_filter_with_snapshot_payload(
423 column_name: &str,
424 column_index: usize,
425 payload_bytes: usize,
426 ) -> Arc<DynamicFilterPhysicalExpr> {
427 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
428 vec![Arc::new(Column::new(column_name, column_index)) as Arc<_>],
429 lit(true) as _,
430 ));
431 dyn_filter
432 .update(lit(ScalarValue::Utf8(Some("x".repeat(payload_bytes)))) as _)
433 .unwrap();
434 dyn_filter
435 }
436
437 fn refreshed_regs(captured: &[CapturedDynFilter]) -> InitialDynFilterRegs {
438 let query_ctx = QueryContext::arc();
439 let region_query_ctx = query_context_with_refreshed_initial_dyn_filter_regs(
440 &query_ctx,
441 RegionId::new(1024, 7),
442 captured,
443 );
444 InitialDynFilterRegs::from_extension_value(
445 region_query_ctx
446 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
447 .unwrap(),
448 )
449 .unwrap()
450 }
451
452 fn decode_snapshot(snapshot: &InitialDynFilterSnapshot, column_name: &str) -> String {
453 snapshot
454 .payload
455 .decode_datafusion_expr(
456 &TaskContext::default(),
457 &arrow_schema::Schema::new(vec![arrow_schema::Field::new(
458 column_name,
459 arrow_schema::DataType::Utf8,
460 false,
461 )]),
462 REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
463 )
464 .unwrap()
465 .to_string()
466 }
467
468 #[test]
469 fn capture_remote_dyn_filters_for_pushdown_preserves_parent_filter_ordinals() {
470 let parent_filters = vec![
471 Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
472 Arc::new(DynamicFilterPhysicalExpr::new(
473 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
474 lit(true) as _,
475 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
476 Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
477 Arc::new(DynamicFilterPhysicalExpr::new(
478 vec![Arc::new(Column::new("pod", 3)) as Arc<_>],
479 lit(true) as _,
480 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
481 ];
482
483 let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
484 let captured =
485 capture_remote_dyn_filters_for_pushdown(remote_dyn_filter_producer_id, parent_filters)
486 .captured_dyn_filters;
487
488 assert_eq!(captured.len(), 2);
489 assert_eq!(
490 captured[0].filter_id.remote_dyn_filter_producer_id(),
491 remote_dyn_filter_producer_id
492 );
493 assert_eq!(
494 captured[1].filter_id.remote_dyn_filter_producer_id(),
495 remote_dyn_filter_producer_id
496 );
497 assert_eq!(captured[0].filter_id.producer_ordinal(), 1);
498 assert_eq!(captured[1].filter_id.producer_ordinal(), 3);
499 }
500
501 #[test]
502 fn capture_remote_dyn_filters_for_pushdown_marks_only_valid_initial_regs() {
503 let parent_filters = vec![
504 Arc::new(Column::new("service", 0)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
505 Arc::new(DynamicFilterPhysicalExpr::new(
506 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
507 lit(true) as _,
508 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
509 Arc::new(Column::new("zone", 2)) as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
510 ];
511
512 let remote_dyn_filter_producer_id = test_remote_dyn_filter_producer_id(42);
513 let pushdown =
514 capture_remote_dyn_filters_for_pushdown(remote_dyn_filter_producer_id, parent_filters);
515
516 assert_eq!(pushdown.pushed_down, vec![false, true, false]);
517 assert_eq!(pushdown.captured_dyn_filters.len(), 1);
518 assert_eq!(
519 pushdown.captured_dyn_filters[0]
520 .filter_id
521 .remote_dyn_filter_producer_id(),
522 remote_dyn_filter_producer_id
523 );
524 assert_eq!(
525 pushdown.captured_dyn_filters[0]
526 .filter_id
527 .producer_ordinal(),
528 1
529 );
530 assert!(
531 pushdown.captured_dyn_filters[0]
532 .initial_registration
533 .initial_snapshot
534 .is_some()
535 );
536 }
537
538 #[test]
539 fn capture_remote_dyn_filters_for_pushdown_rejects_unencodable_registration() {
540 let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
541 vec![Arc::new(UnserializableExpr) as Arc<_>],
542 lit(true) as _,
543 ))
544 as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
545
546 let pushdown = capture_remote_dyn_filters_for_pushdown(
547 test_remote_dyn_filter_producer_id(42),
548 parent_filters,
549 );
550
551 assert_eq!(pushdown.pushed_down, vec![false]);
552 assert!(pushdown.captured_dyn_filters.is_empty());
553 }
554
555 #[test]
556 fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot() {
557 let parent_filters = vec![Arc::new(DynamicFilterPhysicalExpr::new(
558 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
559 lit(true) as _,
560 ))
561 as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
562
563 let pushdown = capture_remote_dyn_filters_for_pushdown(
564 test_remote_dyn_filter_producer_id(42),
565 parent_filters,
566 );
567
568 assert_eq!(pushdown.pushed_down, vec![true]);
569 assert!(
570 pushdown.captured_dyn_filters[0]
571 .initial_registration
572 .initial_snapshot
573 .is_some()
574 );
575 }
576
577 #[test]
578 fn capture_remote_dyn_filters_for_pushdown_attaches_initial_snapshot_after_update() {
579 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
580 vec![Arc::new(Column::new("host", 1)) as Arc<_>],
581 lit(true) as _,
582 ));
583 dyn_filter.update(lit(false) as _).unwrap();
584 let parent_filters = vec![dyn_filter as Arc<dyn datafusion::physical_plan::PhysicalExpr>];
585
586 let pushdown = capture_remote_dyn_filters_for_pushdown(
587 test_remote_dyn_filter_producer_id(42),
588 parent_filters,
589 );
590
591 assert_eq!(pushdown.pushed_down, vec![true]);
592 let snapshot = pushdown.captured_dyn_filters[0]
593 .initial_registration
594 .initial_snapshot
595 .as_ref()
596 .unwrap();
597 assert_eq!(snapshot.generation, 2);
598 assert!(!snapshot.is_complete);
599 assert!(matches!(
600 snapshot.payload,
601 DynFilterPayload::Datafusion(ref bytes) if !bytes.is_empty()
602 ));
603 }
604
605 #[test]
606 fn capture_remote_dyn_filters_for_pushdown_rejects_oversized_snapshots() {
607 let oversized_total_snapshot_bytes = REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES * 3 / 5;
608 let parent_filters = vec![
609 test_dyn_filter_with_snapshot_payload("host", 0, oversized_total_snapshot_bytes)
610 as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
611 test_dyn_filter_with_snapshot_payload("pod", 1, oversized_total_snapshot_bytes)
612 as Arc<dyn datafusion::physical_plan::PhysicalExpr>,
613 ];
614
615 let pushdown = capture_remote_dyn_filters_for_pushdown(
616 test_remote_dyn_filter_producer_id(42),
617 parent_filters,
618 );
619
620 assert_eq!(pushdown.pushed_down, vec![false, false]);
621 assert!(pushdown.captured_dyn_filters.is_empty());
622 }
623
624 #[test]
625 fn capture_remote_dyn_filters_for_pushdown_rejects_too_many_regs_with_snapshots() {
626 const TOO_MANY_INITIAL_REGS: usize = 65;
627
628 let parent_filters = (0..TOO_MANY_INITIAL_REGS)
629 .map(|ordinal| {
630 test_dyn_filter_with_snapshot_payload(&format!("host_{ordinal}"), ordinal, 1)
631 as Arc<dyn datafusion::physical_plan::PhysicalExpr>
632 })
633 .collect::<Vec<_>>();
634
635 let pushdown = capture_remote_dyn_filters_for_pushdown(
636 test_remote_dyn_filter_producer_id(42),
637 parent_filters,
638 );
639
640 assert!(pushdown.captured_dyn_filters.is_empty());
641 assert_eq!(pushdown.pushed_down, vec![false; TOO_MANY_INITIAL_REGS]);
642 }
643
644 #[test]
645 fn capture_remote_dyn_filters_for_pushdown_rejects_regs_exceeding_bounds() {
646 const TOO_MANY_INITIAL_REGS: usize = 65;
647
648 let parent_filters = (0..TOO_MANY_INITIAL_REGS)
649 .map(|_| {
650 Arc::new(DynamicFilterPhysicalExpr::new(
651 vec![Arc::new(Column::new("host", 0)) as Arc<_>],
652 lit(true) as _,
653 )) as Arc<dyn datafusion::physical_plan::PhysicalExpr>
654 })
655 .collect::<Vec<_>>();
656
657 let pushdown = capture_remote_dyn_filters_for_pushdown(
658 test_remote_dyn_filter_producer_id(42),
659 parent_filters,
660 );
661
662 assert!(pushdown.captured_dyn_filters.is_empty());
663 assert_eq!(pushdown.pushed_down, vec![false; TOO_MANY_INITIAL_REGS]);
664 }
665
666 #[test]
667 fn register_dyn_filter_subscribers_for_region_reuses_existing_entry() {
668 let registry = QueryDynFilterRegistry::new(test_query_id(1));
669 let captured_dyn_filters = vec![test_captured_dyn_filter(
670 test_remote_dyn_filter_producer_id(42),
671 2,
672 "host",
673 0,
674 )];
675 let first_region_id = RegionId::new(1024, 7);
676 let second_region_id = RegionId::new(1024, 8);
677
678 register_remote_dyn_filters(®istry, &captured_dyn_filters);
679 register_dyn_filter_subscribers_for_region(
680 ®istry,
681 first_region_id,
682 test_target(1),
683 &captured_dyn_filters,
684 );
685 register_dyn_filter_subscribers_for_region(
686 ®istry,
687 second_region_id,
688 test_target(2),
689 &captured_dyn_filters,
690 );
691
692 assert_eq!(registry.entry_count(), 1);
693 let entry = registry.entries().pop().unwrap();
694 assert_eq!(
695 entry.filter_id().remote_dyn_filter_producer_id(),
696 test_remote_dyn_filter_producer_id(42)
697 );
698 assert_eq!(entry.filter_id().producer_ordinal(), 2);
699 let subscribers = entry.subscribers();
700 assert_eq!(subscribers.len(), 2);
701 assert!(
702 subscribers
703 .iter()
704 .any(|subscriber| subscriber.region_id() == first_region_id)
705 );
706 assert!(
707 subscribers
708 .iter()
709 .any(|subscriber| subscriber.region_id() == second_region_id)
710 );
711 }
712
713 #[test]
714 fn register_remote_dyn_filters_keeps_independent_producer_ids_distinct() {
715 let registry = QueryDynFilterRegistry::new(test_query_id(1));
716 let make_filter = |remote_dyn_filter_producer_id| {
717 test_captured_dyn_filter(remote_dyn_filter_producer_id, 2, "host", 0)
718 };
719
720 register_remote_dyn_filters(
721 ®istry,
722 &[make_filter(test_remote_dyn_filter_producer_id(42))],
723 );
724 register_remote_dyn_filters(
725 ®istry,
726 &[make_filter(test_remote_dyn_filter_producer_id(43))],
727 );
728
729 assert_eq!(registry.entry_count(), 2);
730 }
731
732 #[test]
733 fn query_context_includes_region_initial_dyn_filter_regs() {
734 let captured_dyn_filters = vec![test_captured_dyn_filter(
735 test_remote_dyn_filter_producer_id(42),
736 2,
737 "host",
738 0,
739 )];
740 let region_id = RegionId::new(1024, 7);
741 let query_ctx = QueryContext::arc();
742
743 let region_query_ctx = query_context_with_initial_dyn_filter_regs(
744 &query_ctx,
745 region_id,
746 &captured_dyn_filters,
747 );
748 let extension = region_query_ctx
749 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
750 .unwrap();
751 let regs = InitialDynFilterRegs::from_extension_value(extension).unwrap();
752 let decoded_children = regs.regs[0]
753 .decode_children(
754 &TaskContext::default(),
755 &arrow_schema::Schema::new(vec![arrow_schema::Field::new(
756 "host",
757 arrow_schema::DataType::Utf8,
758 false,
759 )]),
760 1024,
761 )
762 .unwrap();
763 assert_eq!(regs.regs.len(), 1);
764 assert_eq!(
765 regs.regs[0].filter_id,
766 captured_dyn_filters[0].filter_id.to_string()
767 );
768 assert_eq!(decoded_children.len(), 1);
769 assert!(decoded_children[0].as_any().is::<Column>());
770 }
771
772 #[test]
773 fn refreshed_initial_regs_use_live_filter_snapshot_without_mutating_capture() {
774 let dyn_filter = Arc::new(DynamicFilterPhysicalExpr::new(
775 vec![Arc::new(Column::new("host", 0)) as Arc<_>],
776 lit(true) as _,
777 ));
778 let captured = vec![
779 build_captured_dyn_filter(
780 test_remote_dyn_filter_producer_id(42),
781 0,
782 dyn_filter.clone(),
783 )
784 .unwrap(),
785 ];
786 let original_generation = captured[0]
787 .initial_registration
788 .initial_snapshot
789 .as_ref()
790 .unwrap()
791 .generation;
792 dyn_filter.update(lit(false) as _).unwrap();
793 dyn_filter.mark_complete();
794
795 let regs = refreshed_regs(&captured);
796
797 let snapshot = regs.regs[0].initial_snapshot.as_ref().unwrap();
798 assert_eq!(snapshot.generation, 2);
799 assert!(!snapshot.is_complete);
800 assert_ne!(decode_snapshot(snapshot, "host"), "true");
801 assert_eq!(
802 captured[0]
803 .initial_registration
804 .initial_snapshot
805 .as_ref()
806 .unwrap()
807 .generation,
808 original_generation
809 );
810 }
811
812 #[test]
813 fn refresh_keeps_old_snapshot_when_one_live_filter_cannot_encode() {
814 let good = Arc::new(DynamicFilterPhysicalExpr::new(
815 vec![Arc::new(Column::new("good", 0)) as Arc<_>],
816 lit(true) as _,
817 ));
818 let bad = Arc::new(DynamicFilterPhysicalExpr::new(
819 vec![Arc::new(Column::new("bad", 0)) as Arc<_>],
820 lit(true) as _,
821 ));
822 let captured = vec![
823 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 0, good.clone())
824 .unwrap(),
825 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 1, bad.clone())
826 .unwrap(),
827 ];
828 let old_bad_generation = captured[1]
829 .initial_registration
830 .initial_snapshot
831 .as_ref()
832 .unwrap()
833 .generation;
834 good.update(lit(false) as _).unwrap();
835 bad.update(Arc::new(UnserializableExpr) as _).unwrap();
836
837 let regs = refreshed_regs(&captured);
838 assert_eq!(
839 regs.regs[0].initial_snapshot.as_ref().unwrap().generation,
840 2
841 );
842 assert_eq!(
843 regs.regs[1].initial_snapshot.as_ref().unwrap().generation,
844 old_bad_generation
845 );
846 }
847
848 #[test]
849 fn refresh_aggregate_overflow_falls_back_to_original_snapshots() {
850 let payload_bytes = REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES * 3 / 5;
851 let first = test_dyn_filter_with_snapshot_payload("first", 0, 1);
852 let second = test_dyn_filter_with_snapshot_payload("second", 0, 1);
853 let captured = vec![
854 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 0, first.clone())
855 .unwrap(),
856 build_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 1, second.clone())
857 .unwrap(),
858 ];
859 let original = captured
860 .iter()
861 .map(|captured| {
862 captured
863 .initial_registration
864 .initial_snapshot
865 .clone()
866 .unwrap()
867 })
868 .collect::<Vec<_>>();
869 first
870 .update(lit(ScalarValue::Utf8(Some("x".repeat(payload_bytes)))) as _)
871 .unwrap();
872 second
873 .update(lit(ScalarValue::Utf8(Some("y".repeat(payload_bytes)))) as _)
874 .unwrap();
875
876 let regs = refreshed_regs(&captured);
877 for (refreshed, original) in regs.regs.iter().zip(original) {
878 let refreshed = refreshed.initial_snapshot.as_ref().unwrap();
879 assert_eq!(refreshed.generation, original.generation);
880 assert_eq!(refreshed.payload, original.payload);
881 }
882 }
883
884 #[test]
885 fn query_context_drops_initial_regs_when_duplicate_filter_ids_exceed_bounds() {
886 let captured_dyn_filters = vec![
887 test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
888 test_captured_dyn_filter(test_remote_dyn_filter_producer_id(42), 2, "host", 0),
889 ];
890 let region_id = RegionId::new(1024, 7);
891 let query_ctx = QueryContext::arc();
892
893 let region_query_ctx = query_context_with_initial_dyn_filter_regs(
894 &query_ctx,
895 region_id,
896 &captured_dyn_filters,
897 );
898
899 assert!(
900 region_query_ctx
901 .extension(INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY)
902 .is_none()
903 );
904 }
905}