1use std::pin::Pin;
16use std::sync::{Arc, Weak};
17use std::task::{Context, Poll};
18
19use api::region::RegionResponse;
20use api::v1::region::RemoteDynFilterRequest;
21use api::v1::region::remote_dyn_filter_request::Action;
22use common_base::Plugins;
23use common_recordbatch::adapter::RecordBatchMetrics;
24use common_recordbatch::{OrderOption, RecordBatch, RecordBatchStream, SendableRecordBatchStream};
25use common_telemetry::{debug, warn};
26use datafusion_expr::LogicalPlan;
27use futures_util::Stream;
28use query::dist_plan::{
29 RemoteDynFilterReceiverInjector, RemoteDynFilterReceiverInjectorRef,
30 RemoteDynFilterReceiverLogicalPlan,
31};
32use query::options::remote_dyn_filter_pushdown_enabled_from_extensions;
33use query::promql::plan_contains_promql_extension;
34use session::context::QueryContextRef;
35use session::query_id::QueryId;
36use snafu::OptionExt;
37use store_api::storage::RegionId;
38
39use crate::error::{self, Result, UnexpectedSnafu};
40use crate::region_server::registrations::{
41 RemoteDynFilterId, RemoteDynFilterUpdateOutcome, apply_remote_dyn_filter_update,
42 initial_dyn_filter_regs_from_query_ctx, register_initial_dyn_filter_regs,
43 remote_dyn_filter_exprs_for_initial_regs, remove_initial_dyn_filter_regs,
44 unregister_remote_dyn_filter,
45};
46use crate::region_server::{RegionServer, RegionServerInner};
47
48fn remote_dyn_filter_receiver_plan(
49 server: &Weak<RegionServerInner>,
50 origin: LogicalPlan,
51 ctx: QueryContextRef,
52) -> LogicalPlan {
53 if !remote_dyn_filter_pushdown_enabled(&ctx) {
54 return origin;
55 }
56
57 if plan_contains_promql_extension(&origin) {
58 return origin;
59 }
60
61 let Some(query_id) = ctx.remote_query_id_value() else {
62 return origin;
63 };
64
65 let Some(initial_regs) = initial_dyn_filter_regs_from_query_ctx(&ctx) else {
66 return origin;
67 };
68
69 let Some(server) = server.upgrade() else {
70 return origin;
71 };
72
73 let dyn_filters = remote_dyn_filter_exprs_for_initial_regs(
74 &server.initial_remote_dyn_filter_registrations,
75 &query_id,
76 &initial_regs,
77 origin.schema().as_arrow(),
78 );
79
80 if dyn_filters.is_empty() {
81 return origin;
82 }
83
84 RemoteDynFilterReceiverLogicalPlan::new(origin, dyn_filters).into_logical_plan()
85}
86
87fn remote_dyn_filter_pushdown_enabled(query_ctx: &QueryContextRef) -> bool {
88 match remote_dyn_filter_pushdown_enabled_from_extensions(&query_ctx.extensions()) {
89 Ok(enabled) => enabled,
90 Err(error) => {
91 warn!(error; "Remote dynamic filter pushdown is disabled because the query option is invalid");
92 false
93 }
94 }
95}
96
97impl RegionServer {
98 pub fn install_remote_dyn_filter_receiver_injector(&self, plugins: &Plugins) {
99 let server = Arc::downgrade(&self.inner);
100 plugins.insert::<RemoteDynFilterReceiverInjectorRef>(Arc::new(
101 RemoteDynFilterReceiverInjector::new(move |origin, ctx| {
102 remote_dyn_filter_receiver_plan(&server, origin, ctx)
103 }),
104 ));
105 }
106
107 pub(super) fn register_initial_remote_dyn_filter_cleanup(
108 &self,
109 query_ctx: &QueryContextRef,
110 region_id: RegionId,
111 ) -> Option<RemoteDynFilterRegistrationGuard> {
112 if !remote_dyn_filter_pushdown_enabled(query_ctx) {
113 return None;
114 }
115
116 let initial_dyn_filter_regs = initial_dyn_filter_regs_from_query_ctx(query_ctx);
117 let query_id = query_ctx.remote_query_id_value();
118 let registered_filter_ids = if let (Some(query_id), Some(regs)) =
119 (query_id.as_ref(), initial_dyn_filter_regs.as_ref())
120 {
121 register_initial_dyn_filter_regs(
122 &self.inner.initial_remote_dyn_filter_registrations,
123 query_id,
124 region_id,
125 regs,
126 )
127 } else {
128 Vec::new()
129 };
130
131 match (query_id, registered_filter_ids.is_empty()) {
132 (Some(query_id), false) => Some(RemoteDynFilterRegistrationGuard::new(
133 self.clone(),
134 query_id,
135 region_id,
136 registered_filter_ids,
137 )),
138 _ => None,
139 }
140 }
141
142 pub(super) async fn handle_remote_dyn_filter_request(
143 &self,
144 request: &RemoteDynFilterRequest,
145 ) -> Result<RegionResponse> {
146 if request.query_id.is_empty() {
147 return error::MissingRequiredFieldSnafu { name: "query_id" }.fail();
148 }
149
150 let query_id = request.query_id.parse::<QueryId>().map_err(|_| {
151 UnexpectedSnafu {
152 violated: "remote dynamic filter query_id must be a valid QueryId",
153 }
154 .build()
155 })?;
156
157 match request
158 .action
159 .as_ref()
160 .context(error::MissingRequiredFieldSnafu { name: "action" })?
161 {
162 Action::Update(update) => {
163 self.handle_remote_dyn_filter_update(&query_id, update)
164 .await
165 }
166 Action::Unregister(unregister) => {
167 self.handle_remote_dyn_filter_unregister(&query_id, unregister)
168 .await
169 }
170 }
171 }
172
173 async fn handle_remote_dyn_filter_update(
174 &self,
175 query_id: &QueryId,
176 request: &api::v1::region::RemoteDynFilterUpdate,
177 ) -> Result<RegionResponse> {
178 if request.filter_id.is_empty() {
179 return error::MissingRequiredFieldSnafu { name: "filter_id" }.fail();
180 }
181
182 if request.payload.is_empty() {
183 return error::MissingRequiredFieldSnafu { name: "payload" }.fail();
184 }
185
186 let filter_id = RemoteDynFilterId::new(request.filter_id.clone());
187 let outcome = apply_remote_dyn_filter_update(
188 &self.inner.initial_remote_dyn_filter_registrations,
189 query_id,
190 &filter_id,
191 &request.payload,
192 request.generation,
193 request.is_complete,
194 );
195 self.log_remote_dyn_filter_update_outcome(query_id, &filter_id, outcome);
196
197 Ok(RegionResponse::new(0))
198 }
199
200 async fn handle_remote_dyn_filter_unregister(
201 &self,
202 query_id: &QueryId,
203 request: &api::v1::region::RemoteDynFilterUnregister,
204 ) -> Result<RegionResponse> {
205 if request.filter_id.is_empty() {
206 return error::MissingRequiredFieldSnafu { name: "filter_id" }.fail();
207 }
208
209 let filter_id = RemoteDynFilterId::new(request.filter_id.clone());
210 let outcome = unregister_remote_dyn_filter(
211 &self.inner.initial_remote_dyn_filter_registrations,
212 query_id,
213 &filter_id,
214 );
215 self.log_remote_dyn_filter_update_outcome(query_id, &filter_id, outcome);
216
217 Ok(RegionResponse::new(0))
218 }
219
220 fn log_remote_dyn_filter_update_outcome(
221 &self,
222 query_id: &QueryId,
223 filter_id: &RemoteDynFilterId,
224 outcome: RemoteDynFilterUpdateOutcome,
225 ) {
226 if matches!(
227 outcome,
228 RemoteDynFilterUpdateOutcome::AlreadyComplete
229 | RemoteDynFilterUpdateOutcome::PayloadTooLarge
230 | RemoteDynFilterUpdateOutcome::DecodeFailed
231 ) {
232 warn!(
233 "Remote dynamic filter update outcome, query_id: {}, filter_id: {}, outcome: {:?}",
234 query_id, filter_id, outcome
235 );
236 } else {
237 debug!(
238 "Remote dynamic filter update outcome, query_id: {}, filter_id: {}, outcome: {:?}",
239 query_id, filter_id, outcome
240 );
241 }
242 }
243}
244
245pub(super) fn wrap_remote_dyn_filter_guarded_stream(
246 stream: SendableRecordBatchStream,
247 cleanup: RemoteDynFilterRegistrationGuard,
248) -> SendableRecordBatchStream {
249 Box::pin(RemoteDynFilterGuardedStream { stream, cleanup })
250}
251
252pub(super) struct RemoteDynFilterRegistrationGuard {
254 server: RegionServer,
255 query_id: QueryId,
256 region_id: RegionId,
257 filter_ids: Vec<RemoteDynFilterId>,
258 cleaned: bool,
259}
260
261impl RemoteDynFilterRegistrationGuard {
262 fn new(
263 server: RegionServer,
264 query_id: QueryId,
265 region_id: RegionId,
266 filter_ids: Vec<RemoteDynFilterId>,
267 ) -> Self {
268 Self {
269 server,
270 query_id,
271 region_id,
272 filter_ids,
273 cleaned: false,
274 }
275 }
276
277 fn cleanup_once(&mut self) {
278 if self.cleaned {
279 return;
280 }
281
282 remove_initial_dyn_filter_regs(
283 &self.server.inner.initial_remote_dyn_filter_registrations,
284 &self.query_id,
285 self.region_id,
286 &self.filter_ids,
287 );
288 self.cleaned = true;
289 }
290}
291
292impl Drop for RemoteDynFilterRegistrationGuard {
293 fn drop(&mut self) {
294 self.cleanup_once();
295 }
296}
297
298struct RemoteDynFilterGuardedStream {
300 stream: SendableRecordBatchStream,
301 cleanup: RemoteDynFilterRegistrationGuard,
302}
303
304impl RecordBatchStream for RemoteDynFilterGuardedStream {
305 fn name(&self) -> &str {
306 self.stream.name()
307 }
308
309 fn schema(&self) -> datatypes::schema::SchemaRef {
310 self.stream.schema()
311 }
312
313 fn output_ordering(&self) -> Option<&[OrderOption]> {
314 self.stream.output_ordering()
315 }
316
317 fn metrics(&self) -> Option<RecordBatchMetrics> {
318 self.stream.metrics()
319 }
320}
321
322impl Stream for RemoteDynFilterGuardedStream {
323 type Item = common_recordbatch::error::Result<RecordBatch>;
324
325 fn size_hint(&self) -> (usize, Option<usize>) {
326 self.stream.size_hint()
327 }
328
329 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
330 match Pin::new(&mut self.stream).poll_next(cx) {
331 Poll::Ready(None) => {
332 self.cleanup.cleanup_once();
333 Poll::Ready(None)
334 }
335 other => other,
336 }
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use std::assert_matches;
343 use std::collections::{HashMap, HashSet};
344 use std::sync::Arc;
345 use std::time::Duration;
346
347 use api::v1::region::{
348 RemoteDynFilterRequest, RemoteDynFilterUnregister, RemoteDynFilterUpdate,
349 remote_dyn_filter_request,
350 };
351 use common_query::request::{
352 DynFilterPayload, INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
353 InitialDynFilterReg, InitialDynFilterRegs, InitialDynFilterSnapshot,
354 REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES,
355 };
356 use common_recordbatch::RecordBatches;
357 use datafusion::arrow::datatypes::Schema as ArrowSchema;
358 use datafusion::physical_plan::PhysicalExpr;
359 use datafusion::physical_plan::expressions::{DynamicFilterPhysicalExpr, lit as physical_lit};
360 use datafusion_common::DFSchema;
361 use datafusion_expr::EmptyRelation;
362 use datatypes::prelude::{ConcreteDataType, VectorRef};
363 use datatypes::schema::{ColumnSchema, Schema};
364 use datatypes::vectors::Int32Vector;
365 use futures_util::StreamExt;
366 use query::options::QUERY_ENABLE_REMOTE_DYNAMIC_FILTER_PUSHDOWN;
367 use session::context::QueryContext;
368 use session::hints::REMOTE_QUERY_ID_EXTENSION_KEY;
369 use session::query_id::QueryId;
370 use store_api::storage::RegionId;
371
372 use super::*;
373 use crate::region_server::registrations::RemoteDynFilterRegistry;
374 use crate::tests::mock_region_server;
375
376 #[derive(Debug, Clone)]
377 struct RegisteredDynFilterSnapshot {
378 filter_id: RemoteDynFilterId,
379 child_exprs_datafusion_proto: Vec<Vec<u8>>,
380 subscriber_regions: HashSet<RegionId>,
381 }
382
383 fn query_regs(
384 regs_by_query: &RemoteDynFilterRegistry,
385 query_id: &QueryId,
386 ) -> Option<HashMap<RemoteDynFilterId, RegisteredDynFilterSnapshot>> {
387 regs_by_query.inspect_query(query_id, |query_regs| {
388 query_regs
389 .iter()
390 .map(|(filter_id, registered)| {
391 (
392 filter_id.clone(),
393 RegisteredDynFilterSnapshot {
394 filter_id: registered.filter_id.clone(),
395 child_exprs_datafusion_proto: registered
396 .child_exprs_datafusion_proto
397 .clone(),
398 subscriber_regions: registered.subscriber_regions.clone(),
399 },
400 )
401 })
402 .collect()
403 })
404 }
405
406 fn test_remote_query_id() -> QueryId {
407 QueryId::new()
408 }
409
410 fn test_remote_dyn_filter_region_id() -> RegionId {
411 RegionId::new(1024, 7)
412 }
413
414 fn single_value_stream() -> common_recordbatch::SendableRecordBatchStream {
415 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
416 "v",
417 ConcreteDataType::int32_datatype(),
418 false,
419 )]));
420 let values: VectorRef = Arc::new(Int32Vector::from_slice([1]));
421 let batch = common_recordbatch::RecordBatch::new(schema.clone(), vec![values]).unwrap();
422 RecordBatches::try_new(schema, vec![batch])
423 .unwrap()
424 .as_stream()
425 }
426
427 fn empty_logical_plan() -> LogicalPlan {
428 LogicalPlan::EmptyRelation(EmptyRelation {
429 produce_one_row: false,
430 schema: Arc::new(DFSchema::empty()),
431 })
432 }
433
434 fn query_context_with_initial_regs(query_id: QueryId) -> QueryContext {
435 let mut query_ctx = QueryContext::with("greptime", "public");
436 query_ctx.set_extension(REMOTE_QUERY_ID_EXTENSION_KEY, query_id.to_string());
437 query_ctx.set_extension(
438 INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
439 InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])])
440 .to_extension_value()
441 .unwrap(),
442 );
443 query_ctx
444 }
445
446 #[test]
447 fn remote_dyn_filter_receiver_plan_respects_disabled_query_option() {
448 let mock_region_server = mock_region_server();
449 let query_id = test_remote_query_id();
450 let mut query_ctx = query_context_with_initial_regs(query_id);
451 query_ctx.set_extension(QUERY_ENABLE_REMOTE_DYNAMIC_FILTER_PUSHDOWN, "false");
452
453 let plan = remote_dyn_filter_receiver_plan(
454 &Arc::downgrade(&mock_region_server.inner),
455 empty_logical_plan(),
456 Arc::new(query_ctx),
457 );
458
459 assert!(matches!(plan, LogicalPlan::EmptyRelation(_)));
460 }
461
462 #[test]
463 fn remote_dyn_filter_cleanup_registration_respects_disabled_query_option() {
464 let mock_region_server = mock_region_server();
465 let query_id = test_remote_query_id();
466 let mut query_ctx = query_context_with_initial_regs(query_id);
467 query_ctx.set_extension(QUERY_ENABLE_REMOTE_DYNAMIC_FILTER_PUSHDOWN, "false");
468 let query_ctx = Arc::new(query_ctx);
469
470 let cleanup = mock_region_server.register_initial_remote_dyn_filter_cleanup(
471 &query_ctx,
472 test_remote_dyn_filter_region_id(),
473 );
474
475 assert!(cleanup.is_none());
476 assert!(
477 mock_region_server
478 .inner
479 .initial_remote_dyn_filter_registrations
480 .inspect_query(&query_id, |_| ())
481 .is_none()
482 );
483 }
484
485 #[test]
486 fn initial_dyn_filter_regs_can_be_read_from_query_context() {
487 let mut query_ctx = QueryContext::with("greptime", "public");
488 query_ctx.set_extension(
489 INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
490 InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
491 "filter-1",
492 vec![vec![1, 2, 3]],
493 )])
494 .to_extension_value()
495 .unwrap(),
496 );
497
498 let regs = initial_dyn_filter_regs_from_query_ctx(&Arc::new(query_ctx)).unwrap();
499
500 assert_eq!(regs.regs.len(), 1);
501 assert_eq!(regs.regs[0].filter_id, "filter-1");
502 }
503
504 #[test]
505 fn initial_dyn_filter_regs_from_query_context_rejects_duplicate_filter_ids() {
506 let mut query_ctx = QueryContext::with("greptime", "public");
507 query_ctx.set_extension(
508 INITIAL_REMOTE_DYN_FILTER_REGISTRATIONS_EXTENSION_KEY,
509 InitialDynFilterRegs::new(vec![
510 InitialDynFilterReg::new("filter-1", vec![vec![1, 2, 3]]),
511 InitialDynFilterReg::new("filter-1", vec![vec![4, 5, 6]]),
512 ])
513 .to_extension_value()
514 .unwrap(),
515 );
516
517 let regs = initial_dyn_filter_regs_from_query_ctx(&Arc::new(query_ctx));
518
519 assert!(regs.is_none());
520 }
521
522 #[test]
523 fn register_initial_dyn_filter_regs_creates_query_scoped_entries() {
524 let regs_by_query = RemoteDynFilterRegistry::new();
525 let regs = InitialDynFilterRegs::new(vec![
526 InitialDynFilterReg::new("filter-1", vec![vec![1, 2, 3]]),
527 InitialDynFilterReg::new("filter-2", vec![vec![4, 5, 6]]),
528 ]);
529 let query_id = test_remote_query_id();
530 let region_id = test_remote_dyn_filter_region_id();
531
532 let registered_filter_ids =
533 register_initial_dyn_filter_regs(®s_by_query, &query_id, region_id, ®s);
534
535 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
536 assert_eq!(query_regs.len(), 2);
537 assert_eq!(
538 registered_filter_ids,
539 vec![
540 RemoteDynFilterId::new("filter-1"),
541 RemoteDynFilterId::new("filter-2")
542 ]
543 );
544 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
545 assert_eq!(registered.filter_id, RemoteDynFilterId::new("filter-1"));
546 assert_eq!(registered.child_exprs_datafusion_proto, vec![vec![1, 2, 3]]);
547 assert_eq!(registered.subscriber_regions.len(), 1);
548 assert!(registered.subscriber_regions.contains(®ion_id));
549 }
550
551 #[test]
552 fn register_initial_dyn_filter_regs_same_region_duplicate_is_idempotent() {
553 let regs_by_query = RemoteDynFilterRegistry::new();
554 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
555 "filter-1",
556 vec![vec![1, 2, 3]],
557 )]);
558 let query_id = test_remote_query_id();
559 let region_id = test_remote_dyn_filter_region_id();
560
561 let first = register_initial_dyn_filter_regs(®s_by_query, &query_id, region_id, ®s);
562 let duplicate =
563 register_initial_dyn_filter_regs(®s_by_query, &query_id, region_id, ®s);
564
565 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
566 assert_eq!(query_regs.len(), 1);
567 assert_eq!(first, vec![RemoteDynFilterId::new("filter-1")]);
568 assert!(duplicate.is_empty());
569 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
570 assert_eq!(registered.subscriber_regions.len(), 1);
571 assert!(registered.subscriber_regions.contains(®ion_id));
572 }
573
574 #[test]
575 fn register_initial_dyn_filter_regs_ignores_invalid_duplicate_payload_set() {
576 let regs_by_query = RemoteDynFilterRegistry::new();
577 let regs = InitialDynFilterRegs::new(vec![
578 InitialDynFilterReg::new("filter-1", vec![vec![1, 2, 3]]),
579 InitialDynFilterReg::new("filter-1", vec![vec![4, 5, 6]]),
580 ]);
581 let query_id = test_remote_query_id();
582 let region_id = test_remote_dyn_filter_region_id();
583
584 register_initial_dyn_filter_regs(®s_by_query, &query_id, region_id, ®s);
585
586 assert!(query_regs(®s_by_query, &query_id).is_none());
587 }
588
589 #[test]
590 fn register_initial_dyn_filter_regs_tracks_different_region_subscribers_for_same_filter() {
591 let regs_by_query = RemoteDynFilterRegistry::new();
592 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
593 "filter-1",
594 vec![vec![1, 2, 3]],
595 )]);
596 let query_id = test_remote_query_id();
597 let first_region_id = RegionId::new(1024, 7);
598 let second_region_id = RegionId::new(1024, 8);
599
600 register_initial_dyn_filter_regs(®s_by_query, &query_id, first_region_id, ®s);
601 register_initial_dyn_filter_regs(®s_by_query, &query_id, second_region_id, ®s);
602
603 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
604 assert_eq!(query_regs.len(), 1);
605 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
606 assert_eq!(registered.subscriber_regions.len(), 2);
607 assert!(registered.subscriber_regions.contains(&first_region_id));
608 assert!(registered.subscriber_regions.contains(&second_region_id));
609 }
610
611 #[test]
612 fn remove_initial_dyn_filter_regs_removes_registered_filter_entries() {
613 let regs_by_query = RemoteDynFilterRegistry::new();
614 let query_id = test_remote_query_id();
615 let other_query_id = test_remote_query_id();
616 let region_id = test_remote_dyn_filter_region_id();
617
618 let registered_filter_ids = register_initial_dyn_filter_regs(
619 ®s_by_query,
620 &query_id,
621 region_id,
622 &InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
623 "filter-1",
624 vec![vec![1, 2, 3]],
625 )]),
626 );
627 register_initial_dyn_filter_regs(
628 ®s_by_query,
629 &other_query_id,
630 region_id,
631 &InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
632 "filter-2",
633 vec![vec![4, 5, 6]],
634 )]),
635 );
636
637 remove_initial_dyn_filter_regs(
638 ®s_by_query,
639 &query_id,
640 region_id,
641 ®istered_filter_ids,
642 );
643
644 assert!(query_regs(®s_by_query, &query_id).is_none());
645 let other_query_regs = query_regs(®s_by_query, &other_query_id).unwrap();
646 assert_eq!(other_query_regs.len(), 1);
647 }
648
649 #[test]
650 fn remove_initial_dyn_filter_regs_keeps_other_subscribers() {
651 let regs_by_query = RemoteDynFilterRegistry::new();
652 let query_id = test_remote_query_id();
653 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
654 "filter-1",
655 vec![vec![1, 2, 3]],
656 )]);
657 let first_region_id = RegionId::new(1024, 7);
658 let second_region_id = RegionId::new(1024, 8);
659
660 let first_subscription =
661 register_initial_dyn_filter_regs(®s_by_query, &query_id, first_region_id, ®s);
662 register_initial_dyn_filter_regs(®s_by_query, &query_id, second_region_id, ®s);
663
664 remove_initial_dyn_filter_regs(
665 ®s_by_query,
666 &query_id,
667 first_region_id,
668 &first_subscription,
669 );
670
671 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
672 assert_eq!(query_regs.len(), 1);
673 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
674 assert_eq!(registered.subscriber_regions.len(), 1);
675 assert!(registered.subscriber_regions.contains(&second_region_id));
676 }
677
678 #[tokio::test]
679 async fn test_handle_remote_dyn_filter_request_requires_query_id() {
680 let mock_region_server = mock_region_server();
681
682 let err = mock_region_server
683 .handle_remote_dyn_filter_request(&RemoteDynFilterRequest {
684 query_id: String::new(),
685 action: Some(remote_dyn_filter_request::Action::Unregister(
686 RemoteDynFilterUnregister {
687 filter_id: "filter-1".to_string(),
688 },
689 )),
690 })
691 .await
692 .unwrap_err();
693
694 assert_matches!(
695 err,
696 crate::error::Error::MissingRequiredField { ref name, .. } if name == "query_id"
697 );
698 }
699
700 #[tokio::test]
701 async fn test_handle_remote_dyn_filter_request_requires_action() {
702 let mock_region_server = mock_region_server();
703
704 let err = mock_region_server
705 .handle_remote_dyn_filter_request(&RemoteDynFilterRequest {
706 query_id: test_remote_query_id().to_string(),
707 action: None,
708 })
709 .await
710 .unwrap_err();
711
712 assert_matches!(
713 err,
714 crate::error::Error::MissingRequiredField { ref name, .. } if name == "action"
715 );
716 }
717
718 #[tokio::test]
719 async fn test_handle_remote_dyn_filter_update_requires_filter_id() {
720 let mock_region_server = mock_region_server();
721
722 let err = mock_region_server
723 .handle_remote_dyn_filter_request(&RemoteDynFilterRequest {
724 query_id: test_remote_query_id().to_string(),
725 action: Some(remote_dyn_filter_request::Action::Update(
726 RemoteDynFilterUpdate {
727 filter_id: String::new(),
728 payload: vec![1],
729 generation: 1,
730 is_complete: false,
731 },
732 )),
733 })
734 .await
735 .unwrap_err();
736
737 assert_matches!(
738 err,
739 crate::error::Error::MissingRequiredField { ref name, .. } if name == "filter_id"
740 );
741 }
742
743 #[tokio::test]
744 async fn test_handle_remote_dyn_filter_update_requires_payload() {
745 let mock_region_server = mock_region_server();
746
747 let err = mock_region_server
748 .handle_remote_dyn_filter_request(&RemoteDynFilterRequest {
749 query_id: test_remote_query_id().to_string(),
750 action: Some(remote_dyn_filter_request::Action::Update(
751 RemoteDynFilterUpdate {
752 filter_id: "filter-1".to_string(),
753 payload: Vec::new(),
754 generation: 1,
755 is_complete: false,
756 },
757 )),
758 })
759 .await
760 .unwrap_err();
761
762 assert_matches!(
763 err,
764 crate::error::Error::MissingRequiredField { ref name, .. } if name == "payload"
765 );
766 }
767
768 #[test]
769 fn test_apply_remote_dyn_filter_update_missing_registration() {
770 let regs_by_query = RemoteDynFilterRegistry::new();
771 let query_id = test_remote_query_id();
772 let filter_id = RemoteDynFilterId::new("filter-1");
773
774 let outcome =
775 apply_remote_dyn_filter_update(®s_by_query, &query_id, &filter_id, &[1], 1, false);
776 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::MissingRegistration);
777
778 let outcome = unregister_remote_dyn_filter(®s_by_query, &query_id, &filter_id);
779 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::MissingRegistration);
780 }
781
782 #[test]
783 fn test_apply_remote_dyn_filter_update_buffering_before_scan() {
784 let regs_by_query = RemoteDynFilterRegistry::new();
785 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new(
786 "filter-1",
787 vec![vec![1, 2, 3]],
788 )]);
789 let query_id = test_remote_query_id();
790 let filter_id = RemoteDynFilterId::new("filter-1");
791
792 register_initial_dyn_filter_regs(
793 ®s_by_query,
794 &query_id,
795 test_remote_dyn_filter_region_id(),
796 ®s,
797 );
798
799 let outcome =
801 apply_remote_dyn_filter_update(®s_by_query, &query_id, &filter_id, &[1], 1, false);
802 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Buffered);
803
804 let outcome =
806 apply_remote_dyn_filter_update(®s_by_query, &query_id, &filter_id, &[2], 0, false);
807 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Stale);
808
809 let outcome =
811 apply_remote_dyn_filter_update(®s_by_query, &query_id, &filter_id, &[3], 1, false);
812 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Idempotent);
813 }
814
815 fn datafusion_payload_bytes(expr: Arc<dyn PhysicalExpr>) -> Vec<u8> {
816 match DynFilterPayload::from_datafusion_expr(&expr, REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES)
817 .unwrap()
818 {
819 DynFilterPayload::Datafusion(bytes) => bytes,
820 _ => unreachable!(
821 "DynFilterPayload::from_datafusion_expr only returns datafusion payloads"
822 ),
823 }
824 }
825
826 fn empty_arrow_schema() -> ArrowSchema {
827 ArrowSchema::empty()
828 }
829
830 fn register_empty_remote_dyn_filter(
831 regs_by_query: &RemoteDynFilterRegistry,
832 query_id: &QueryId,
833 ) -> Vec<RemoteDynFilterId> {
834 register_empty_remote_dyn_filter_for_region(
835 regs_by_query,
836 query_id,
837 test_remote_dyn_filter_region_id(),
838 )
839 }
840
841 fn register_empty_remote_dyn_filter_for_region(
842 regs_by_query: &RemoteDynFilterRegistry,
843 query_id: &QueryId,
844 region_id: RegionId,
845 ) -> Vec<RemoteDynFilterId> {
846 register_initial_dyn_filter_regs(
847 regs_by_query,
848 query_id,
849 region_id,
850 &InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])]),
851 )
852 }
853
854 #[test]
855 fn initial_remote_dyn_filter_snapshot_initializes_runtime_filter() {
856 let regs_by_query = RemoteDynFilterRegistry::new();
857 let query_id = test_remote_query_id();
858 let payload = DynFilterPayload::Datafusion(datafusion_payload_bytes(physical_lit(false)));
859 let regs = InitialDynFilterRegs::new(vec![
860 InitialDynFilterReg::new("filter-1", vec![])
861 .with_initial_snapshot(InitialDynFilterSnapshot::new(payload, 7, false)),
862 ]);
863
864 register_initial_dyn_filter_regs(
865 ®s_by_query,
866 &query_id,
867 test_remote_dyn_filter_region_id(),
868 ®s,
869 );
870 let exprs = remote_dyn_filter_exprs_for_initial_regs(
871 ®s_by_query,
872 &query_id,
873 ®s,
874 &empty_arrow_schema(),
875 );
876
877 assert_eq!(exprs.len(), 1);
878 assert_eq!(format!("{}", exprs[0]), "DynamicFilter [ false ]");
879 }
880
881 fn only_remote_dyn_filter(
882 regs_by_query: &RemoteDynFilterRegistry,
883 query_id: &QueryId,
884 ) -> Arc<DynamicFilterPhysicalExpr> {
885 let initial_regs =
886 InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])]);
887 let exprs = remote_dyn_filter_exprs_for_initial_regs(
888 regs_by_query,
889 query_id,
890 &initial_regs,
891 &empty_arrow_schema(),
892 );
893 assert_eq!(1, exprs.len());
894 let expr = exprs.into_iter().next().unwrap();
895 let expr = expr as Arc<dyn std::any::Any + Send + Sync>;
896 expr.downcast::<DynamicFilterPhysicalExpr>().unwrap()
897 }
898
899 #[test]
900 fn test_remote_dyn_filter_rejects_oversized_payload_before_buffering() {
901 let regs_by_query = RemoteDynFilterRegistry::new();
902 let query_id = test_remote_query_id();
903 let filter_id = RemoteDynFilterId::new("filter-1");
904 register_empty_remote_dyn_filter(®s_by_query, &query_id);
905
906 let oversized = vec![0; REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES + 1];
907 let outcome = apply_remote_dyn_filter_update(
908 ®s_by_query,
909 &query_id,
910 &filter_id,
911 &oversized,
912 1,
913 false,
914 );
915 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::PayloadTooLarge);
916
917 let outcome =
919 apply_remote_dyn_filter_update(®s_by_query, &query_id, &filter_id, &[1], 0, false);
920 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Buffered);
921 }
922
923 #[test]
924 fn test_remote_dyn_filter_generation_zero_applies_as_first_update() {
925 let regs_by_query = RemoteDynFilterRegistry::new();
926 let query_id = test_remote_query_id();
927 let filter_id = RemoteDynFilterId::new("filter-1");
928 register_empty_remote_dyn_filter(®s_by_query, &query_id);
929
930 let dyn_filter = only_remote_dyn_filter(®s_by_query, &query_id);
932 let payload = datafusion_payload_bytes(physical_lit(false));
933 let outcome = apply_remote_dyn_filter_update(
934 ®s_by_query,
935 &query_id,
936 &filter_id,
937 &payload,
938 0,
939 false,
940 );
941
942 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
943 assert!(dyn_filter.snapshot_generation() > 1);
944 assert_eq!(format!("{}", dyn_filter.current().unwrap()), "false");
945 }
946
947 #[test]
948 fn test_buffered_update_applies_when_scan_installs_wrapper() {
949 let regs_by_query = RemoteDynFilterRegistry::new();
950 let query_id = test_remote_query_id();
951 let filter_id = RemoteDynFilterId::new("filter-1");
952 register_empty_remote_dyn_filter(®s_by_query, &query_id);
953
954 let payload = datafusion_payload_bytes(physical_lit(false));
955 let outcome = apply_remote_dyn_filter_update(
956 ®s_by_query,
957 &query_id,
958 &filter_id,
959 &payload,
960 1,
961 false,
962 );
963 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Buffered);
964
965 let dyn_filter = only_remote_dyn_filter(®s_by_query, &query_id);
966 assert!(dyn_filter.snapshot_generation() > 1);
967 assert_eq!(format!("{}", dyn_filter.current().unwrap()), "false");
968 }
969
970 #[tokio::test]
971 async fn test_unregister_completes_installed_remote_dyn_filter_without_relaxing() {
972 let regs_by_query = RemoteDynFilterRegistry::new();
973 let query_id = test_remote_query_id();
974 let filter_id = RemoteDynFilterId::new("filter-1");
975 register_empty_remote_dyn_filter(®s_by_query, &query_id);
976
977 let dyn_filter = only_remote_dyn_filter(®s_by_query, &query_id);
978 let payload = datafusion_payload_bytes(physical_lit(false));
979 let outcome = apply_remote_dyn_filter_update(
980 ®s_by_query,
981 &query_id,
982 &filter_id,
983 &payload,
984 1,
985 false,
986 );
987 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
988 assert_eq!(format!("{}", dyn_filter.current().unwrap()), "false");
989
990 let outcome = unregister_remote_dyn_filter(®s_by_query, &query_id, &filter_id);
991 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
992 assert!(query_regs(®s_by_query, &query_id).is_none());
993 tokio::time::timeout(Duration::from_secs(1), dyn_filter.wait_complete())
994 .await
995 .unwrap();
996 assert_eq!(format!("{}", dyn_filter.current().unwrap()), "false");
997 }
998
999 #[tokio::test]
1000 async fn test_remote_dyn_filter_unregister_removes_all_region_subscribers_for_filter() {
1001 let regs_by_query = RemoteDynFilterRegistry::new();
1002 let query_id = test_remote_query_id();
1003 let filter_id = RemoteDynFilterId::new("filter-1");
1004 let first_region_id = RegionId::new(1024, 7);
1005 let second_region_id = RegionId::new(1024, 8);
1006 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])]);
1007
1008 let first_subscription =
1009 register_initial_dyn_filter_regs(®s_by_query, &query_id, first_region_id, ®s);
1010 let second_subscription =
1011 register_initial_dyn_filter_regs(®s_by_query, &query_id, second_region_id, ®s);
1012 let dyn_filter = only_remote_dyn_filter(®s_by_query, &query_id);
1013
1014 let payload = datafusion_payload_bytes(physical_lit(false));
1015 let outcome = apply_remote_dyn_filter_update(
1016 ®s_by_query,
1017 &query_id,
1018 &filter_id,
1019 &payload,
1020 1,
1021 false,
1022 );
1023 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
1024
1025 let outcome = unregister_remote_dyn_filter(®s_by_query, &query_id, &filter_id);
1026 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
1027 assert!(query_regs(®s_by_query, &query_id).is_none());
1028 tokio::time::timeout(Duration::from_secs(1), dyn_filter.wait_complete())
1029 .await
1030 .unwrap();
1031 assert_eq!(format!("{}", dyn_filter.current().unwrap()), "false");
1032
1033 remove_initial_dyn_filter_regs(
1035 ®s_by_query,
1036 &query_id,
1037 first_region_id,
1038 &first_subscription,
1039 );
1040 remove_initial_dyn_filter_regs(
1041 ®s_by_query,
1042 &query_id,
1043 second_region_id,
1044 &second_subscription,
1045 );
1046 assert!(query_regs(®s_by_query, &query_id).is_none());
1047 }
1048
1049 #[test]
1050 fn test_remote_dyn_filter_unregister_keeps_other_filters_for_same_query() {
1051 let regs_by_query = RemoteDynFilterRegistry::new();
1052 let query_id = test_remote_query_id();
1053 let region_id = test_remote_dyn_filter_region_id();
1054
1055 register_initial_dyn_filter_regs(
1056 ®s_by_query,
1057 &query_id,
1058 region_id,
1059 &InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])]),
1060 );
1061 register_initial_dyn_filter_regs(
1062 ®s_by_query,
1063 &query_id,
1064 region_id,
1065 &InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-2", vec![])]),
1066 );
1067
1068 let outcome = unregister_remote_dyn_filter(
1069 ®s_by_query,
1070 &query_id,
1071 &RemoteDynFilterId::new("filter-1"),
1072 );
1073 assert_eq!(outcome, RemoteDynFilterUpdateOutcome::Applied);
1074
1075 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
1076 assert!(!query_regs.contains_key(&RemoteDynFilterId::new("filter-1")));
1077 assert!(query_regs.contains_key(&RemoteDynFilterId::new("filter-2")));
1078 }
1079
1080 #[tokio::test]
1081 async fn test_remote_dyn_filter_guarded_stream_removes_on_eof() {
1082 let mock_region_server = mock_region_server();
1083 let query_id = test_remote_query_id();
1084 let region_id = test_remote_dyn_filter_region_id();
1085 let registered_filter_ids = register_empty_remote_dyn_filter(
1086 &mock_region_server
1087 .inner
1088 .initial_remote_dyn_filter_registrations,
1089 &query_id,
1090 );
1091 let cleanup = RemoteDynFilterRegistrationGuard::new(
1092 mock_region_server.clone(),
1093 query_id,
1094 region_id,
1095 registered_filter_ids,
1096 );
1097
1098 let stream = wrap_remote_dyn_filter_guarded_stream(single_value_stream(), cleanup);
1099 let mut pinned = Box::pin(stream);
1100 while pinned.next().await.is_some() {}
1101
1102 assert!(
1103 mock_region_server
1104 .inner
1105 .initial_remote_dyn_filter_registrations
1106 .inspect_query(&query_id, |_| ())
1107 .is_none()
1108 );
1109 }
1110
1111 #[tokio::test]
1112 async fn test_remote_dyn_filter_multi_region_subscription_cleanup() {
1113 let regs_by_query = RemoteDynFilterRegistry::new();
1114 let regs = InitialDynFilterRegs::new(vec![InitialDynFilterReg::new("filter-1", vec![])]);
1115 let query_id = test_remote_query_id();
1116 let first_region_id = RegionId::new(1024, 7);
1117 let second_region_id = RegionId::new(1024, 8);
1118
1119 let first_subscription =
1121 register_initial_dyn_filter_regs(®s_by_query, &query_id, first_region_id, ®s);
1122 let second_subscription =
1123 register_initial_dyn_filter_regs(®s_by_query, &query_id, second_region_id, ®s);
1124 let dyn_filter = only_remote_dyn_filter(®s_by_query, &query_id);
1125
1126 {
1128 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
1129 assert_eq!(query_regs.len(), 1);
1130 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
1131 assert_eq!(registered.subscriber_regions.len(), 2);
1132 assert!(registered.subscriber_regions.contains(&first_region_id));
1133 assert!(registered.subscriber_regions.contains(&second_region_id));
1134 }
1135
1136 remove_initial_dyn_filter_regs(
1138 ®s_by_query,
1139 &query_id,
1140 first_region_id,
1141 &first_subscription,
1142 );
1143 assert!(query_regs(®s_by_query, &query_id).is_some());
1144 assert!(
1145 tokio::time::timeout(Duration::from_millis(50), dyn_filter.wait_complete())
1146 .await
1147 .is_err()
1148 );
1149 {
1150 let query_regs = query_regs(®s_by_query, &query_id).unwrap();
1151 let registered = query_regs.get(&RemoteDynFilterId::new("filter-1")).unwrap();
1152 assert_eq!(registered.subscriber_regions.len(), 1);
1153 assert!(registered.subscriber_regions.contains(&second_region_id));
1154 }
1155
1156 remove_initial_dyn_filter_regs(
1158 ®s_by_query,
1159 &query_id,
1160 second_region_id,
1161 &second_subscription,
1162 );
1163 assert!(query_regs(®s_by_query, &query_id).is_none());
1164 tokio::time::timeout(Duration::from_secs(1), dyn_filter.wait_complete())
1165 .await
1166 .unwrap();
1167 }
1168}