Skip to main content

query/dist_plan/
dyn_filter_bridge.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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    /// Preflight result per parent filter.
45    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        &current,
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    // Current DataFusion exposes `wait_complete()`, but no non-blocking completion getter.
210    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, &regs)
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(&registry, &captured_dyn_filters);
679        register_dyn_filter_subscribers_for_region(
680            &registry,
681            first_region_id,
682            test_target(1),
683            &captured_dyn_filters,
684        );
685        register_dyn_filter_subscribers_for_region(
686            &registry,
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            &registry,
722            &[make_filter(test_remote_dyn_filter_producer_id(42))],
723        );
724        register_remote_dyn_filters(
725            &registry,
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}