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