1use std::collections::{HashMap, HashSet};
16use std::future::Future;
17use std::sync::{Arc, Mutex, RwLock, Weak};
18use std::time::Duration;
19
20use api::v1::region::{RemoteDynFilterUnregister, RemoteDynFilterUpdate};
21use common_query::request::{DynFilterPayload, REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES};
22use common_runtime::spawn_global;
23use common_telemetry::{debug, warn};
24use datafusion_physical_expr::PhysicalExpr;
25use datafusion_physical_expr::expressions::DynamicFilterPhysicalExpr;
26use session::query_id::QueryId;
27use store_api::storage::RegionId;
28use tokio::sync::{Notify, watch};
29
30use crate::dist_plan::FilterId;
31use crate::metrics::{
32 REMOTE_DYN_FILTER_ENCODE_TOTAL, REMOTE_DYN_FILTER_PAYLOAD_BYTES,
33 REMOTE_DYN_FILTER_UPDATE_RPC_TOTAL,
34};
35use crate::region_query::{RegionQueryHandlerRef, RegionQueryTarget};
36
37const REMOTE_DYN_FILTER_RECONCILE_INTERVAL: Duration = Duration::from_secs(1);
38const REMOTE_DYN_FILTER_CONTROL_RPC_TIMEOUT: Duration = Duration::from_secs(10);
40
41#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct Subscriber {
44 region_id: RegionId,
45 target: RegionQueryTarget,
46}
47
48impl Subscriber {
49 pub fn new(region_id: RegionId, target: RegionQueryTarget) -> Self {
50 Self { region_id, target }
51 }
52
53 pub fn region_id(&self) -> RegionId {
54 self.region_id
55 }
56
57 pub fn target(&self) -> &RegionQueryTarget {
58 &self.target
59 }
60}
61
62#[derive(Debug, Clone)]
64pub enum EntryRegistration {
65 Inserted(Arc<DynFilterEntry>),
66 Existing(Arc<DynFilterEntry>),
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum SubscriberRegistration {
73 Added,
74 Duplicate,
75 MissingFilter,
76}
77
78#[derive(Debug)]
80pub struct DynFilterEntry {
81 filter_id: FilterId,
82 producer_filter: Weak<DynamicFilterPhysicalExpr>,
83 subscribers: RwLock<HashSet<Subscriber>>,
84 state: Mutex<DynFilterEntryState>,
85 subscriber_changed: Notify,
86}
87
88#[derive(Debug, Default)]
89struct DynFilterEntryState {
90 last_sent_generation: u64,
91 unregistered: bool,
92 fanout_started: bool,
93}
94
95#[derive(Debug)]
96struct QueryDynFilterRegistryInner {
97 entries: HashMap<FilterId, Arc<DynFilterEntry>>,
98}
99
100impl DynFilterEntry {
101 pub fn new(filter_id: FilterId, producer_filter: Arc<DynamicFilterPhysicalExpr>) -> Self {
102 Self {
103 filter_id,
104 producer_filter: Arc::downgrade(&producer_filter),
105 subscribers: RwLock::new(HashSet::new()),
106 state: Mutex::new(DynFilterEntryState::default()),
107 subscriber_changed: Notify::new(),
108 }
109 }
110
111 pub fn filter_id(&self) -> &FilterId {
112 &self.filter_id
113 }
114
115 pub fn upgrade_producer_filter(&self) -> Option<Arc<DynamicFilterPhysicalExpr>> {
116 self.producer_filter.upgrade()
117 }
118
119 pub fn subscribers(&self) -> Vec<Subscriber> {
120 self.subscribers.read().unwrap().iter().cloned().collect()
121 }
122
123 pub fn register_subscriber(&self, subscriber: Subscriber) -> bool {
124 let mut subscribers = self.subscribers.write().unwrap();
125 subscribers.insert(subscriber)
126 }
127
128 fn mark_generation_sent(&self, generation: u64) -> bool {
129 let mut state = self.state.lock().unwrap();
130 if generation <= state.last_sent_generation {
131 return false;
132 }
133
134 state.last_sent_generation = generation;
135 true
136 }
137
138 fn try_mark_unregistered(&self) -> bool {
139 let mut state = self.state.lock().unwrap();
140 if state.unregistered {
141 return false;
142 }
143
144 state.unregistered = true;
145 true
146 }
147
148 fn reactivate_for_new_subscriber(&self) {
149 {
150 let mut state = self.state.lock().unwrap();
151 state.last_sent_generation = 0;
153 state.unregistered = false;
154 }
155 self.subscriber_changed.notify_one();
156 }
157
158 fn mark_fanout_started(&self) -> bool {
159 let mut state = self.state.lock().unwrap();
160 if state.fanout_started {
161 return false;
162 }
163
164 state.fanout_started = true;
165 true
166 }
167
168 #[cfg(test)]
169 pub(crate) fn fanout_started_for_test(&self) -> bool {
170 self.state.lock().unwrap().fanout_started
171 }
172}
173
174#[derive(Debug)]
176pub struct QueryDynFilterRegistry {
177 query_id: QueryId,
178 lifecycle_tx: watch::Sender<()>,
179 inner: RwLock<QueryDynFilterRegistryInner>,
180}
181
182impl QueryDynFilterRegistry {
183 pub fn new(query_id: QueryId) -> Self {
184 let (lifecycle_tx, _) = watch::channel(());
186 Self {
187 query_id,
188 lifecycle_tx,
189 inner: RwLock::new(QueryDynFilterRegistryInner {
190 entries: HashMap::new(),
191 }),
192 }
193 }
194
195 pub fn query_id(&self) -> QueryId {
196 self.query_id
197 }
198
199 pub fn entry_count(&self) -> usize {
200 self.inner.read().unwrap().entries.len()
201 }
202
203 pub fn entries(&self) -> Vec<Arc<DynFilterEntry>> {
204 self.inner
205 .read()
206 .unwrap()
207 .entries
208 .values()
209 .cloned()
210 .collect()
211 }
212
213 pub fn remote_dyn_filter(&self, filter_id: &FilterId) -> Option<Arc<DynFilterEntry>> {
214 self.inner.read().unwrap().entries.get(filter_id).cloned()
215 }
216
217 pub fn register_remote_dyn_filter(
218 &self,
219 filter_id: FilterId,
220 producer_filter: Arc<DynamicFilterPhysicalExpr>,
221 ) -> EntryRegistration {
222 let mut inner = self.inner.write().unwrap();
223 if let Some(existing) = inner.entries.get(&filter_id) {
224 return EntryRegistration::Existing(existing.clone());
225 }
226
227 let entry = Arc::new(DynFilterEntry::new(filter_id.clone(), producer_filter));
228 inner.entries.insert(filter_id, entry.clone());
229 EntryRegistration::Inserted(entry)
230 }
231
232 pub fn register_subscriber(
233 &self,
234 filter_id: &FilterId,
235 subscriber: Subscriber,
236 ) -> SubscriberRegistration {
237 let Some(entry) = self.inner.read().unwrap().entries.get(filter_id).cloned() else {
238 return SubscriberRegistration::MissingFilter;
239 };
240
241 if entry.register_subscriber(subscriber) {
242 entry.reactivate_for_new_subscriber();
244 SubscriberRegistration::Added
245 } else {
246 SubscriberRegistration::Duplicate
247 }
248 }
249
250 pub(crate) fn remove_subscriber(&self, filter_id: &FilterId, subscriber: &Subscriber) -> bool {
252 self.inner
253 .read()
254 .unwrap()
255 .entries
256 .get(filter_id)
257 .is_some_and(|entry| entry.subscribers.write().unwrap().remove(subscriber))
258 }
259
260 pub fn ensure_fanout_task(self: &Arc<Self>, region_query_handler: RegionQueryHandlerRef) {
264 for entry in self.entries() {
265 ensure_entry_fanout_task(
266 self.query_id,
267 entry,
268 region_query_handler.clone(),
269 self.lifecycle_tx.subscribe(),
270 );
271 }
272 }
273
274 #[cfg(test)]
275 async fn fanout_snapshot(
276 &self,
277 region_query_handler: &RegionQueryHandlerRef,
278 entry: &DynFilterEntry,
279 filter: &DynamicFilterPhysicalExpr,
280 is_complete: bool,
281 ) {
282 let mut lifecycle_rx = self.lifecycle_tx.subscribe();
283 fanout_snapshot_for_query(
284 self.query_id,
285 region_query_handler,
286 entry,
287 filter,
288 is_complete,
289 &mut lifecycle_rx,
290 REMOTE_DYN_FILTER_CONTROL_RPC_TIMEOUT,
291 )
292 .await;
293 }
294
295 #[cfg(test)]
296 async fn unregister_all_once(&self, region_query_handler: &RegionQueryHandlerRef) {
297 for entry in self.entries() {
298 unregister_entry_once_for_query(region_query_handler, self.query_id, &entry).await;
299 }
300 }
301}
302
303fn ensure_entry_fanout_task(
304 query_id: QueryId,
305 entry: Arc<DynFilterEntry>,
306 region_query_handler: RegionQueryHandlerRef,
307 lifecycle_rx: watch::Receiver<()>,
308) {
309 if !entry.mark_fanout_started() {
310 return;
311 }
312
313 let _handle = spawn_global(async move {
314 run_entry_fanout(query_id, entry, region_query_handler, lifecycle_rx).await;
315 });
316}
317
318async fn run_entry_fanout(
319 query_id: QueryId,
320 entry: Arc<DynFilterEntry>,
321 region_query_handler: RegionQueryHandlerRef,
322 mut lifecycle_rx: watch::Receiver<()>,
323) {
324 let mut is_complete = false;
325 let mut reconcile_interval = tokio::time::interval_at(
327 tokio::time::Instant::now() + REMOTE_DYN_FILTER_RECONCILE_INTERVAL,
328 REMOTE_DYN_FILTER_RECONCILE_INTERVAL,
329 );
330 reconcile_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
331
332 loop {
333 let Some(filter) = entry.upgrade_producer_filter() else {
334 unregister_entry_once_for_query(®ion_query_handler, query_id, &entry).await;
335 return;
336 };
337
338 if !fanout_snapshot_for_query(
339 query_id,
340 ®ion_query_handler,
341 &entry,
342 &filter,
343 is_complete,
344 &mut lifecycle_rx,
345 REMOTE_DYN_FILTER_CONTROL_RPC_TIMEOUT,
346 )
347 .await
348 {
349 break;
350 }
351
352 if is_complete {
353 tokio::select! {
354 _ = entry.subscriber_changed.notified() => {}
355 result = lifecycle_rx.changed() => {
356 if result.is_err() {
357 break;
358 }
359 }
360 }
361 continue;
362 }
363
364 tokio::select! {
365 _ = filter.wait_update() => {}
366 _ = filter.wait_complete() => {
367 is_complete = true;
368 }
369 _ = reconcile_interval.tick() => {}
372 _ = entry.subscriber_changed.notified() => {}
373 result = lifecycle_rx.changed() => {
374 if result.is_err() {
375 break;
376 }
377 }
378 }
379 }
380
381 unregister_entry_once_for_query(®ion_query_handler, query_id, &entry).await;
382}
383
384async fn fanout_snapshot_for_query(
385 query_id: QueryId,
386 region_query_handler: &RegionQueryHandlerRef,
387 entry: &DynFilterEntry,
388 filter: &DynamicFilterPhysicalExpr,
389 is_complete: bool,
390 lifecycle_rx: &mut watch::Receiver<()>,
391 control_rpc_timeout: Duration,
392) -> bool {
393 let Some((generation, current)) = current_stable_snapshot(filter, lifecycle_rx).await else {
394 return true;
395 };
396
397 if !is_complete && !entry.mark_generation_sent(generation) {
401 return true;
402 }
403
404 if is_complete {
405 let _ = entry.mark_generation_sent(generation);
406 }
407
408 let payload =
409 match DynFilterPayload::from_datafusion_expr(¤t, REMOTE_DYN_FILTER_PAYLOAD_MAX_BYTES)
410 {
411 Ok(DynFilterPayload::Datafusion(payload)) => {
412 REMOTE_DYN_FILTER_ENCODE_TOTAL
413 .with_label_values(&["success"])
414 .inc();
415 REMOTE_DYN_FILTER_PAYLOAD_BYTES.observe(payload.len() as f64);
416 payload
417 }
418 Ok(_) => {
419 REMOTE_DYN_FILTER_ENCODE_TOTAL
420 .with_label_values(&["unsupported"])
421 .inc();
422 warn!("Ignored unsupported remote dynamic filter producer payload");
423 return true;
424 }
425 Err(error) => {
426 REMOTE_DYN_FILTER_ENCODE_TOTAL
427 .with_label_values(&["error"])
428 .inc();
429 warn!(error; "Failed to encode remote dynamic filter producer snapshot");
430 return true;
431 }
432 };
433
434 fanout_update_for_query(
435 query_id,
436 region_query_handler,
437 entry,
438 generation,
439 is_complete,
440 payload,
441 lifecycle_rx,
442 control_rpc_timeout,
443 )
444 .await
445}
446
447#[allow(clippy::too_many_arguments)]
448async fn fanout_update_for_query(
449 query_id: QueryId,
450 region_query_handler: &RegionQueryHandlerRef,
451 entry: &DynFilterEntry,
452 generation: u64,
453 is_complete: bool,
454 payload: Vec<u8>,
455 lifecycle_rx: &mut watch::Receiver<()>,
456 control_rpc_timeout: Duration,
457) -> bool {
458 let query_id = query_id.to_string();
459 let filter_id = entry.filter_id().to_string();
460
461 for subscriber in entry.subscribers() {
462 let update = RemoteDynFilterUpdate {
463 filter_id: filter_id.clone(),
464 payload: payload.clone(),
465 generation,
466 is_complete,
467 };
468
469 match await_control_rpc_or_lifecycle_close(
470 lifecycle_rx,
471 format!(
472 "update query_id={} filter_id={} region_id={}",
473 query_id,
474 filter_id,
475 subscriber.region_id()
476 ),
477 region_query_handler.handle_remote_dyn_filter_update(
478 subscriber.target(),
479 query_id.clone(),
480 update,
481 ),
482 control_rpc_timeout,
483 )
484 .await
485 {
486 ControlRpcResult::Ok(result) => {
487 if let Err(error) = result {
488 REMOTE_DYN_FILTER_UPDATE_RPC_TOTAL
489 .with_label_values(&["error"])
490 .inc();
491 warn!(
492 error;
493 "Failed to fan out remote dynamic filter update, query_id={}, filter_id={}, region_id={}",
494 query_id,
495 filter_id,
496 subscriber.region_id()
497 );
498 } else {
499 REMOTE_DYN_FILTER_UPDATE_RPC_TOTAL
500 .with_label_values(&["success"])
501 .inc();
502 }
503 }
504 ControlRpcResult::TimedOut => {
505 REMOTE_DYN_FILTER_UPDATE_RPC_TOTAL
506 .with_label_values(&["timeout"])
507 .inc();
508 }
509 ControlRpcResult::LifecycleClosed => {
510 REMOTE_DYN_FILTER_UPDATE_RPC_TOTAL
511 .with_label_values(&["cancelled"])
512 .inc();
513 return false;
514 }
515 }
516 }
517
518 true
519}
520
521async fn unregister_entry_once_for_query(
522 region_query_handler: &RegionQueryHandlerRef,
523 query_id: QueryId,
524 entry: &DynFilterEntry,
525) {
526 if !entry.try_mark_unregistered() {
527 return;
528 }
529
530 let query_id = query_id.to_string();
531 let filter_id = entry.filter_id().to_string();
532
533 for subscriber in entry.subscribers() {
534 let unregister = RemoteDynFilterUnregister {
535 filter_id: filter_id.clone(),
536 };
537
538 let Some(result) = await_control_rpc_timeout(
539 format!(
540 "unregister query_id={} filter_id={} region_id={}",
541 query_id,
542 filter_id,
543 subscriber.region_id()
544 ),
545 region_query_handler.handle_remote_dyn_filter_unregister(
546 subscriber.target(),
547 query_id.clone(),
548 unregister,
549 ),
550 )
551 .await
552 else {
553 continue;
554 };
555
556 if let Err(error) = result {
557 warn!(
558 error;
559 "Failed to fan out remote dynamic filter unregister, query_id={}, filter_id={}, region_id={}",
560 query_id,
561 filter_id,
562 subscriber.region_id()
563 );
564 }
565 }
566
567 debug!("Remote dynamic filter producer unregistered subscribers");
568}
569
570enum ControlRpcResult<T> {
571 Ok(T),
572 TimedOut,
573 LifecycleClosed,
574}
575
576async fn await_control_rpc_or_lifecycle_close<T>(
577 lifecycle_rx: &mut watch::Receiver<()>,
578 operation: String,
579 rpc: impl Future<Output = T>,
580 control_rpc_timeout: Duration,
581) -> ControlRpcResult<T> {
582 if lifecycle_rx.has_changed().is_err() {
583 return ControlRpcResult::LifecycleClosed;
584 }
585
586 tokio::select! {
587 biased;
588 result = lifecycle_rx.changed() => {
589 if result.is_err() {
590 debug!("Cancelled remote dynamic filter control RPC after lifecycle close");
591 }
592 ControlRpcResult::LifecycleClosed
593 }
594 result = rpc => ControlRpcResult::Ok(result),
595 _ = tokio::time::sleep(control_rpc_timeout) => {
596 warn!("Timed out remote dynamic filter control RPC: {}", operation);
597 ControlRpcResult::TimedOut
598 }
599 }
600}
601
602async fn await_control_rpc_timeout<T>(
603 operation: String,
604 rpc: impl Future<Output = T>,
605) -> Option<T> {
606 tokio::select! {
607 result = rpc => Some(result),
608 _ = tokio::time::sleep(REMOTE_DYN_FILTER_CONTROL_RPC_TIMEOUT) => {
609 warn!("Timed out remote dynamic filter control RPC: {}", operation);
610 None
611 }
612 }
613}
614
615async fn current_stable_snapshot(
616 filter: &DynamicFilterPhysicalExpr,
617 lifecycle_rx: &mut watch::Receiver<()>,
618) -> Option<(u64, Arc<dyn PhysicalExpr>)> {
619 loop {
620 if lifecycle_rx.has_changed().is_err() {
621 return None;
622 }
623
624 let before = filter.snapshot_generation();
625 let current = match filter.current() {
626 Ok(current) => current,
627 Err(error) => {
628 warn!(error; "Failed to read remote dynamic filter producer snapshot");
629 return None;
630 }
631 };
632 let after = filter.snapshot_generation();
633
634 if before == after {
635 return Some((after, current));
636 }
637
638 tokio::select! {
639 biased;
640 result = lifecycle_rx.changed() => {
641 if result.is_err() {
642 return None;
643 }
644 }
645 _ = tokio::task::yield_now() => {}
646 }
647 }
648}
649
650#[derive(Debug)]
654pub struct RemoteDynFilterRegistryLease {
655 registry_manager: Arc<DynFilterRegistryManager>,
656 registry: Option<Arc<QueryDynFilterRegistry>>,
660}
661
662impl RemoteDynFilterRegistryLease {
663 fn new(
664 registry_manager: Arc<DynFilterRegistryManager>,
665 registry: Arc<QueryDynFilterRegistry>,
666 ) -> Self {
667 Self {
668 registry_manager,
669 registry: Some(registry),
670 }
671 }
672
673 pub fn registry(&self) -> &QueryDynFilterRegistry {
674 self.registry
675 .as_deref()
676 .expect("remote dyn filter registry lease must hold a registry")
677 }
678
679 pub fn ensure_fanout_task(&self, region_query_handler: RegionQueryHandlerRef) {
680 self.registry
681 .as_ref()
682 .expect("remote dyn filter registry lease must hold a registry")
683 .ensure_fanout_task(region_query_handler);
684 }
685
686 #[cfg(test)]
687 pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
688 Arc::ptr_eq(
689 self.registry.as_ref().unwrap(),
690 other.registry.as_ref().unwrap(),
691 )
692 }
693
694 #[cfg(test)]
695 pub(crate) fn registry_arc_for_test(&self) -> Arc<QueryDynFilterRegistry> {
696 self.registry.as_ref().unwrap().clone()
697 }
698}
699
700impl Drop for RemoteDynFilterRegistryLease {
701 fn drop(&mut self) {
702 let Some(registry) = self.registry.take() else {
703 return;
704 };
705 let query_id = registry.query_id();
706 let registry_weak = Arc::downgrade(®istry);
707
708 drop(registry);
710
711 let _ = self
712 .registry_manager
713 .remove_if_dropped_registry(&query_id, ®istry_weak);
714 }
715}
716
717#[derive(Debug, Default)]
721pub struct DynFilterRegistryManager {
722 registries: RwLock<HashMap<QueryId, Weak<QueryDynFilterRegistry>>>,
723}
724
725impl DynFilterRegistryManager {
726 #[cfg(test)]
727 fn get(&self, query_id: &QueryId) -> Option<Arc<QueryDynFilterRegistry>> {
728 let (registry, stale_entry) = {
729 let registries = self.registries.read().unwrap();
730 let registry = registries.get(query_id)?;
731
732 (registry.upgrade(), registry.clone())
733 };
734
735 if registry.is_none() {
736 self.remove_stale_entry(query_id, &stale_entry);
737 }
738
739 registry
740 }
741
742 #[cfg(test)]
743 fn remove(&self, query_id: &QueryId) -> Option<Weak<QueryDynFilterRegistry>> {
744 self.registries.write().unwrap().remove(query_id)
745 }
746
747 fn remove_if_dropped_registry(
748 &self,
749 query_id: &QueryId,
750 dropped_registry: &Weak<QueryDynFilterRegistry>,
751 ) -> Option<Weak<QueryDynFilterRegistry>> {
752 let mut registries = self
753 .registries
754 .write()
755 .unwrap_or_else(|poisoned| poisoned.into_inner());
756 let current = registries.get(query_id)?;
757
758 if current.ptr_eq(dropped_registry) && current.upgrade().is_none() {
760 registries.remove(query_id)
761 } else {
762 None
763 }
764 }
765
766 #[cfg(test)]
767 fn remove_stale_entry(
768 &self,
769 query_id: &QueryId,
770 stale_registry: &Weak<QueryDynFilterRegistry>,
771 ) {
772 let mut registries = self.registries.write().unwrap();
773 let Some(current) = registries.get(query_id) else {
774 return;
775 };
776
777 if current.ptr_eq(stale_registry) && current.upgrade().is_none() {
778 registries.remove(query_id);
779 }
780 }
781
782 pub fn acquire_lease(self: &Arc<Self>, query_id: QueryId) -> RemoteDynFilterRegistryLease {
786 let registry = self.get_or_init(query_id);
787 RemoteDynFilterRegistryLease::new(self.clone(), registry)
788 }
789
790 fn get_or_init(&self, query_id: QueryId) -> Arc<QueryDynFilterRegistry> {
791 let mut registries = self.registries.write().unwrap();
792
793 if let Some(registry) = registries.get(&query_id).and_then(Weak::upgrade) {
794 return registry;
795 }
796
797 let registry = Arc::new(QueryDynFilterRegistry::new(query_id));
798 registries.insert(query_id, Arc::downgrade(®istry));
799 registry
800 }
801
802 #[cfg(test)]
803 pub fn registry_count(&self) -> usize {
804 self.registries
806 .read()
807 .unwrap()
808 .values()
809 .filter(|registry| registry.strong_count() > 0)
810 .count()
811 }
812
813 #[cfg(test)]
814 fn weak_entry_count(&self) -> usize {
815 self.registries.read().unwrap().len()
816 }
817}
818
819#[cfg(test)]
820mod tests {
821 use std::collections::HashSet;
822 use std::sync::atomic::{AtomicBool, Ordering};
823 use std::sync::{Barrier, Mutex};
824 use std::thread;
825 use std::time::Duration;
826
827 use api::v1::region::{RemoteDynFilterUnregister, RemoteDynFilterUpdate};
828 use async_trait::async_trait;
829 use common_meta::peer::Peer;
830 use common_query::request::QueryRequest;
831 use datafusion_physical_expr::expressions::{Column, lit};
832 use session::ReadPreference;
833 use uuid::Uuid;
834
835 use super::*;
836 use crate::dist_plan::{FilterFingerprint, RemoteDynFilterProducerId};
837 use crate::error::Result as QueryResult;
838 use crate::region_query::{RegionQueryHandler, RegionQueryTarget};
839
840 #[derive(Debug, Clone, PartialEq, Eq)]
841 struct RecordedUpdate {
842 target: RegionQueryTarget,
843 query_id: String,
844 filter_id: String,
845 generation: u64,
846 is_complete: bool,
847 payload: Vec<u8>,
848 }
849
850 #[derive(Debug, Clone, PartialEq, Eq)]
851 struct RecordedUnregister {
852 target: RegionQueryTarget,
853 query_id: String,
854 filter_id: String,
855 }
856
857 #[derive(Default)]
858 struct RecordingRegionQueryHandler {
859 updates: Mutex<Vec<RecordedUpdate>>,
860 unregisters: Mutex<Vec<RecordedUnregister>>,
861 block_next_update: AtomicBool,
862 update_blocked: Notify,
863 release_update: Notify,
864 }
865
866 impl RecordingRegionQueryHandler {
867 fn updates(&self) -> Vec<RecordedUpdate> {
868 self.updates.lock().unwrap().clone()
869 }
870
871 fn unregisters(&self) -> Vec<RecordedUnregister> {
872 self.unregisters.lock().unwrap().clone()
873 }
874
875 fn block_next_update(&self) {
876 self.block_next_update.store(true, Ordering::SeqCst);
877 }
878
879 async fn wait_for_blocked_update(&self) {
880 self.update_blocked.notified().await;
881 }
882
883 fn release_blocked_update(&self) {
884 self.release_update.notify_one();
885 }
886
887 async fn wait_for_update_count(&self, expected: usize) {
888 for _ in 0..300 {
889 if self.updates().len() >= expected {
890 return;
891 }
892 tokio::time::sleep(Duration::from_millis(10)).await;
893 }
894 panic!("timed out waiting for {expected} remote dyn filter updates");
895 }
896
897 async fn wait_for_complete_update(&self) {
898 for _ in 0..300 {
899 if self.updates().iter().any(|update| update.is_complete) {
900 return;
901 }
902 tokio::time::sleep(Duration::from_millis(10)).await;
903 }
904 panic!("timed out waiting for completed remote dyn filter update");
905 }
906
907 async fn wait_for_unregister_count(&self, expected: usize) {
908 for _ in 0..300 {
909 if self.unregisters().len() >= expected {
910 return;
911 }
912 tokio::time::sleep(Duration::from_millis(10)).await;
913 }
914 panic!("timed out waiting for {expected} remote dyn filter unregisters");
915 }
916 }
917
918 async fn wait_for_registry_drop(registry: Weak<QueryDynFilterRegistry>) {
919 for _ in 0..300 {
920 if registry.upgrade().is_none() {
921 return;
922 }
923 tokio::time::sleep(Duration::from_millis(10)).await;
924 }
925 panic!("timed out waiting for remote dyn filter registry drop");
926 }
927
928 #[async_trait]
929 impl RegionQueryHandler for RecordingRegionQueryHandler {
930 async fn select_target(
931 &self,
932 _read_preference: ReadPreference,
933 _region_id: RegionId,
934 ) -> QueryResult<RegionQueryTarget> {
935 unreachable!("remote dyn filter registry tests should not execute remote queries")
936 }
937
938 async fn do_get(
939 &self,
940 _target: &RegionQueryTarget,
941 _request: QueryRequest,
942 ) -> QueryResult<common_recordbatch::SendableRecordBatchStream> {
943 unreachable!("remote dyn filter registry tests should not execute remote queries")
944 }
945
946 async fn handle_remote_dyn_filter_update(
947 &self,
948 target: &RegionQueryTarget,
949 query_id: String,
950 update: RemoteDynFilterUpdate,
951 ) -> QueryResult<()> {
952 let should_block = self.block_next_update.swap(false, Ordering::SeqCst);
953 self.updates.lock().unwrap().push(RecordedUpdate {
954 target: target.clone(),
955 query_id,
956 filter_id: update.filter_id,
957 generation: update.generation,
958 is_complete: update.is_complete,
959 payload: update.payload,
960 });
961 if should_block {
962 self.update_blocked.notify_one();
963 self.release_update.notified().await;
964 }
965 Ok(())
966 }
967
968 async fn handle_remote_dyn_filter_unregister(
969 &self,
970 target: &RegionQueryTarget,
971 query_id: String,
972 unregister: RemoteDynFilterUnregister,
973 ) -> QueryResult<()> {
974 self.unregisters.lock().unwrap().push(RecordedUnregister {
975 target: target.clone(),
976 query_id,
977 filter_id: unregister.filter_id,
978 });
979 Ok(())
980 }
981 }
982
983 fn test_query_id(value: u128) -> QueryId {
984 QueryId::from(Uuid::from_u128(value))
985 }
986
987 fn test_target(id: u64) -> RegionQueryTarget {
988 RegionQueryTarget::new(Peer {
989 id,
990 addr: format!("127.0.0.1:{id}"),
991 })
992 }
993
994 fn test_filter_id(producer_ordinal: u32) -> FilterId {
995 FilterId::new(
996 RemoteDynFilterProducerId::new(42),
997 producer_ordinal,
998 FilterFingerprint::new(0xabc),
999 )
1000 }
1001
1002 fn test_dyn_filter(names: &[&str]) -> Arc<DynamicFilterPhysicalExpr> {
1003 let children = names
1004 .iter()
1005 .enumerate()
1006 .map(|(index, name)| Arc::new(Column::new(name, index)) as _)
1007 .collect();
1008
1009 Arc::new(DynamicFilterPhysicalExpr::new(children, lit(true) as _))
1010 }
1011
1012 #[test]
1013 fn registry_manager_returns_same_registry_for_same_query() {
1014 let manager = Arc::new(DynFilterRegistryManager::default());
1015 let query_id = test_query_id(1);
1016 let first = manager.acquire_lease(query_id);
1017 let second = manager.acquire_lease(query_id);
1018
1019 assert!(first.ptr_eq(&second));
1020 assert_eq!(manager.registry_count(), 1);
1021 assert_eq!(manager.weak_entry_count(), 1);
1022 }
1023
1024 #[test]
1025 fn registry_manager_removes_registry_for_query() {
1026 let manager = Arc::new(DynFilterRegistryManager::default());
1027 let query_id = test_query_id(1);
1028
1029 let lease = manager.acquire_lease(query_id);
1030
1031 assert!(
1032 manager
1033 .remove(&query_id)
1034 .unwrap()
1035 .ptr_eq(&Arc::downgrade(lease.registry.as_ref().unwrap()))
1036 );
1037 assert!(manager.get(&query_id).is_none());
1038 assert_eq!(manager.registry_count(), 0);
1039 assert_eq!(manager.weak_entry_count(), 0);
1040 }
1041
1042 #[test]
1043 fn registry_manager_lease_waits_for_last_query_scoped_stream() {
1044 let manager = Arc::new(DynFilterRegistryManager::default());
1045 let query_id = test_query_id(1);
1046
1047 let first = manager.acquire_lease(query_id);
1048 let second = manager.acquire_lease(query_id);
1049
1050 assert!(first.ptr_eq(&second));
1051 assert_eq!(manager.registry_count(), 1);
1052 assert_eq!(manager.weak_entry_count(), 1);
1053 drop(first);
1054 assert_eq!(manager.registry_count(), 1);
1055 assert_eq!(manager.weak_entry_count(), 1);
1056
1057 drop(second);
1058 assert_eq!(manager.registry_count(), 0);
1059 assert_eq!(manager.weak_entry_count(), 0);
1060 }
1061
1062 #[test]
1063 fn registry_manager_lease_does_not_remove_reacquired_registry() {
1064 let manager = Arc::new(DynFilterRegistryManager::default());
1065 let query_id = test_query_id(1);
1066
1067 let first = manager.acquire_lease(query_id);
1068 drop(first);
1069 assert_eq!(manager.registry_count(), 0);
1070 assert_eq!(manager.weak_entry_count(), 0);
1071
1072 let second = manager.acquire_lease(query_id);
1073
1074 assert_eq!(manager.registry_count(), 1);
1075 assert_eq!(manager.weak_entry_count(), 1);
1076 drop(second);
1077 assert_eq!(manager.registry_count(), 0);
1078 assert_eq!(manager.weak_entry_count(), 0);
1079 }
1080
1081 #[test]
1082 fn registry_manager_concurrent_final_lease_drop_cleans_weak_entry() {
1083 let manager = Arc::new(DynFilterRegistryManager::default());
1084 let query_id = test_query_id(1);
1085 let first = manager.acquire_lease(query_id);
1086 let second = manager.acquire_lease(query_id);
1087 let barrier = Arc::new(Barrier::new(3));
1088
1089 let first_barrier = barrier.clone();
1090 let first_drop = thread::spawn(move || {
1091 first_barrier.wait();
1092 drop(first);
1093 });
1094
1095 let second_barrier = barrier.clone();
1096 let second_drop = thread::spawn(move || {
1097 second_barrier.wait();
1098 drop(second);
1099 });
1100
1101 barrier.wait();
1102 first_drop.join().unwrap();
1103 second_drop.join().unwrap();
1104
1105 assert_eq!(manager.registry_count(), 0);
1106 assert_eq!(manager.weak_entry_count(), 0);
1107 }
1108
1109 #[test]
1110 fn registry_manager_concurrent_first_acquire_shares_registry() {
1111 let manager = Arc::new(DynFilterRegistryManager::default());
1112 let query_id = test_query_id(1);
1113 let worker_count = 8;
1114 let barrier = Arc::new(Barrier::new(worker_count + 1));
1115
1116 let handles = (0..worker_count)
1117 .map(|_| {
1118 let manager = manager.clone();
1119 let barrier = barrier.clone();
1120 thread::spawn(move || {
1121 barrier.wait();
1122 manager.acquire_lease(query_id)
1123 })
1124 })
1125 .collect::<Vec<_>>();
1126
1127 barrier.wait();
1128 let leases = handles
1129 .into_iter()
1130 .map(|handle| handle.join().unwrap())
1131 .collect::<Vec<_>>();
1132
1133 let first = leases.first().unwrap();
1134 assert!(leases.iter().all(|lease| first.ptr_eq(lease)));
1135 assert_eq!(manager.registry_count(), 1);
1136 assert_eq!(manager.weak_entry_count(), 1);
1137
1138 drop(leases);
1139 assert_eq!(manager.registry_count(), 0);
1140 assert_eq!(manager.weak_entry_count(), 0);
1141 }
1142
1143 #[test]
1144 fn registry_manager_drop_racing_acquire_does_not_leave_stale_entry() {
1145 let manager = Arc::new(DynFilterRegistryManager::default());
1146 let query_id = test_query_id(1);
1147
1148 for _ in 0..64 {
1149 let old_lease = manager.acquire_lease(query_id);
1150 let barrier = Arc::new(Barrier::new(3));
1151
1152 let drop_barrier = barrier.clone();
1153 let drop_thread = thread::spawn(move || {
1154 drop_barrier.wait();
1155 drop(old_lease);
1156 });
1157
1158 let acquire_manager = manager.clone();
1159 let acquire_barrier = barrier.clone();
1160 let acquire_thread = thread::spawn(move || {
1161 acquire_barrier.wait();
1162 acquire_manager.acquire_lease(query_id)
1163 });
1164
1165 barrier.wait();
1166 drop_thread.join().unwrap();
1167 let new_lease = acquire_thread.join().unwrap();
1168
1169 assert_eq!(manager.registry_count(), 1);
1170 assert_eq!(manager.weak_entry_count(), 1);
1171 drop(new_lease);
1172 assert_eq!(manager.registry_count(), 0);
1173 assert_eq!(manager.weak_entry_count(), 0);
1174 }
1175 }
1176
1177 #[test]
1178 fn registry_manager_old_drop_cannot_remove_replacement_registry() {
1179 let manager = Arc::new(DynFilterRegistryManager::default());
1180 let query_id = test_query_id(1);
1181 let old_lease = manager.acquire_lease(query_id);
1182 let old_registry = Arc::downgrade(old_lease.registry.as_ref().unwrap());
1183
1184 drop(old_lease);
1185 assert_eq!(manager.registry_count(), 0);
1186 assert_eq!(manager.weak_entry_count(), 0);
1187
1188 let replacement_lease = manager.acquire_lease(query_id);
1189 assert_eq!(manager.registry_count(), 1);
1190 assert_eq!(manager.weak_entry_count(), 1);
1191
1192 assert!(
1193 manager
1194 .remove_if_dropped_registry(&query_id, &old_registry)
1195 .is_none(),
1196 "old registry cleanup must not remove the replacement weak entry"
1197 );
1198 assert_eq!(manager.registry_count(), 1);
1199 assert_eq!(manager.weak_entry_count(), 1);
1200
1201 drop(replacement_lease);
1202 assert_eq!(manager.registry_count(), 0);
1203 assert_eq!(manager.weak_entry_count(), 0);
1204 }
1205
1206 #[test]
1207 fn registry_stores_filter_and_deduplicates_subscribers() {
1208 let registry = QueryDynFilterRegistry::new(test_query_id(1));
1209 let filter = test_dyn_filter(&["host"]);
1210 let filter_id = test_filter_id(1);
1211 let entry = match registry.register_remote_dyn_filter(filter_id.clone(), filter.clone()) {
1212 EntryRegistration::Inserted(entry) => entry,
1213 other => panic!("unexpected registration result: {other:?}"),
1214 };
1215
1216 assert_eq!(entry.filter_id(), &filter_id);
1217 assert_eq!(registry.entry_count(), 1);
1218
1219 let subscriber = Subscriber::new(RegionId::new(1024, 1), test_target(1));
1220 assert_eq!(
1221 registry.register_subscriber(&filter_id, subscriber.clone()),
1222 SubscriberRegistration::Added
1223 );
1224 assert_eq!(
1225 registry.register_subscriber(&filter_id, subscriber),
1226 SubscriberRegistration::Duplicate
1227 );
1228 assert_eq!(entry.subscribers().len(), 1);
1229 }
1230
1231 #[test]
1232 fn remove_subscriber_removes_only_exact_key() {
1233 let registry = QueryDynFilterRegistry::new(test_query_id(1));
1234 let filter = test_dyn_filter(&["host"]);
1235 let filter_id = test_filter_id(1);
1236 let entry = match registry.register_remote_dyn_filter(filter_id.clone(), filter) {
1237 EntryRegistration::Inserted(entry) => entry,
1238 other => panic!("unexpected registration result: {other:?}"),
1239 };
1240 let first = Subscriber::new(RegionId::new(1024, 1), test_target(1));
1241 let second = Subscriber::new(RegionId::new(1024, 1), test_target(2));
1242 assert_eq!(
1243 registry.register_subscriber(&filter_id, first.clone()),
1244 SubscriberRegistration::Added
1245 );
1246 assert_eq!(
1247 registry.register_subscriber(&filter_id, second.clone()),
1248 SubscriberRegistration::Added
1249 );
1250
1251 assert!(registry.remove_subscriber(&filter_id, &first));
1252 assert!(!registry.remove_subscriber(&filter_id, &first));
1253 assert_eq!(entry.subscribers(), vec![second]);
1254 assert!(!entry.fanout_started_for_test());
1255 }
1256
1257 #[test]
1258 fn subscriber_identity_includes_region_and_target() {
1259 let first_region = RegionId::new(1024, 1);
1260 let second_region = RegionId::new(1024, 2);
1261 let first_target = test_target(1);
1262 let second_target = test_target(2);
1263 let first = Subscriber::new(first_region, first_target.clone());
1264
1265 let mut subscribers = HashSet::new();
1266 assert!(subscribers.insert(first.clone()));
1267 assert!(!subscribers.insert(first));
1268 assert!(subscribers.insert(Subscriber::new(first_region, second_target)));
1269 assert!(subscribers.insert(Subscriber::new(second_region, first_target)));
1270 assert_eq!(subscribers.len(), 3);
1271 }
1272
1273 #[tokio::test]
1274 async fn fanout_sends_changed_generations_to_subscribers() {
1275 let query_id = test_query_id(1);
1276 let registry = Arc::new(QueryDynFilterRegistry::new(query_id));
1277 let filter = test_dyn_filter(&["host"]);
1278 let filter_id = test_filter_id(1);
1279 let entry = match registry.register_remote_dyn_filter(filter_id.clone(), filter.clone()) {
1280 EntryRegistration::Inserted(entry) => entry,
1281 other => panic!("unexpected registration result: {other:?}"),
1282 };
1283 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1284 assert_eq!(
1285 registry.register_subscriber(&filter_id, subscriber.clone()),
1286 SubscriberRegistration::Added
1287 );
1288
1289 let handler = Arc::new(RecordingRegionQueryHandler::default());
1290 let handler_ref = handler.clone() as RegionQueryHandlerRef;
1291
1292 registry
1293 .fanout_snapshot(&handler_ref, &entry, filter.as_ref(), false)
1294 .await;
1295 let updates = handler.updates();
1296 assert_eq!(updates.len(), 1);
1297 assert_eq!(&updates[0].target, subscriber.target());
1298 assert_eq!(updates[0].query_id, query_id.to_string());
1299 assert_eq!(updates[0].filter_id, filter_id.to_string());
1300 assert_eq!(updates[0].generation, filter.snapshot_generation());
1301 assert!(!updates[0].is_complete);
1302 assert!(!updates[0].payload.is_empty());
1303
1304 registry
1305 .fanout_snapshot(&handler_ref, &entry, filter.as_ref(), false)
1306 .await;
1307 assert_eq!(handler.updates().len(), 1);
1308
1309 filter.update(lit(false) as _).unwrap();
1310 registry
1311 .fanout_snapshot(&handler_ref, &entry, filter.as_ref(), false)
1312 .await;
1313 let updates = handler.updates();
1314 assert_eq!(updates.len(), 2);
1315 assert_eq!(updates[1].generation, filter.snapshot_generation());
1316
1317 let second_subscriber = Subscriber::new(RegionId::new(1024, 8), test_target(2));
1318 assert_eq!(
1319 registry.register_subscriber(&filter_id, second_subscriber.clone()),
1320 SubscriberRegistration::Added
1321 );
1322 registry
1323 .fanout_snapshot(&handler_ref, &entry, filter.as_ref(), false)
1324 .await;
1325 let updates = handler.updates();
1326 assert_eq!(updates.len(), 4);
1327 assert!(
1328 updates[2..]
1329 .iter()
1330 .any(|update| update.target == subscriber.target().clone())
1331 );
1332 assert!(
1333 updates[2..]
1334 .iter()
1335 .any(|update| update.target == second_subscriber.target().clone())
1336 );
1337 assert_eq!(entry.subscribers().len(), 2);
1338 }
1339
1340 #[tokio::test]
1341 async fn fanout_task_waits_for_dynamic_filter_notifications() {
1342 let query_id = test_query_id(3);
1343 let manager = Arc::new(DynFilterRegistryManager::default());
1344 let lease = manager.acquire_lease(query_id);
1345 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1346 let filter = test_dyn_filter(&["host"]);
1347 let filter_id = test_filter_id(1);
1348 let _ = lease
1349 .registry()
1350 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1351 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1352 assert_eq!(
1353 lease
1354 .registry()
1355 .register_subscriber(&filter_id, subscriber.clone()),
1356 SubscriberRegistration::Added
1357 );
1358
1359 let handler = Arc::new(RecordingRegionQueryHandler::default());
1360 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1361
1362 handler.wait_for_update_count(1).await;
1363 let initial_generation = handler.updates()[0].generation;
1364
1365 filter.update(lit(false) as _).unwrap();
1366 handler.wait_for_update_count(2).await;
1367 let updates = handler.updates();
1368 assert!(updates[1].generation > initial_generation);
1369 assert_eq!(&updates[1].target, subscriber.target());
1370 assert_eq!(updates[1].filter_id, filter_id.to_string());
1371
1372 filter.mark_complete();
1373 handler.wait_for_update_count(3).await;
1374 let updates = handler.updates();
1375 assert!(updates[2].is_complete);
1376
1377 drop(lease);
1378 handler.wait_for_unregister_count(1).await;
1379 let unregisters = handler.unregisters();
1380 assert_eq!(&unregisters[0].target, subscriber.target());
1381 assert_eq!(unregisters[0].target, updates[0].target);
1382 assert_eq!(unregisters[0].filter_id, filter_id.to_string());
1383
1384 wait_for_registry_drop(registry_weak).await;
1385 }
1386
1387 #[tokio::test]
1388 async fn late_subscriber_receives_completed_snapshot_at_its_target() {
1389 let query_id = test_query_id(10);
1390 let manager = Arc::new(DynFilterRegistryManager::default());
1391 let lease = manager.acquire_lease(query_id);
1392 let filter = test_dyn_filter(&["host"]);
1393 let filter_id = test_filter_id(1);
1394 let _ = lease
1395 .registry()
1396 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1397
1398 filter.update(lit(false) as _).unwrap();
1401 filter.mark_complete();
1402
1403 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(7));
1404 assert_eq!(
1405 lease
1406 .registry()
1407 .register_subscriber(&filter_id, subscriber.clone()),
1408 SubscriberRegistration::Added
1409 );
1410
1411 let handler = Arc::new(RecordingRegionQueryHandler::default());
1412 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1413 handler.wait_for_complete_update().await;
1414
1415 let updates = handler.updates();
1416 let latest = updates.last().unwrap();
1417 assert_eq!(&latest.target, subscriber.target());
1418 assert_eq!(latest.generation, filter.snapshot_generation());
1419 assert!(latest.is_complete);
1420 }
1421
1422 #[tokio::test]
1423 async fn repeated_ensure_fanout_task_keeps_single_watcher() {
1424 let query_id = test_query_id(6);
1425 let manager = Arc::new(DynFilterRegistryManager::default());
1426 let lease = manager.acquire_lease(query_id);
1427 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1428 let filter = test_dyn_filter(&["host"]);
1429 let filter_id = test_filter_id(1);
1430 let entry = match lease
1431 .registry()
1432 .register_remote_dyn_filter(filter_id.clone(), filter.clone())
1433 {
1434 EntryRegistration::Inserted(entry) => entry,
1435 other => panic!("unexpected registration result: {other:?}"),
1436 };
1437 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1438 assert_eq!(
1439 lease
1440 .registry()
1441 .register_subscriber(&filter_id, subscriber.clone()),
1442 SubscriberRegistration::Added
1443 );
1444
1445 let handler = Arc::new(RecordingRegionQueryHandler::default());
1446 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1447 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1448
1449 assert!(entry.fanout_started_for_test());
1450 handler.wait_for_update_count(1).await;
1451 tokio::time::sleep(Duration::from_millis(50)).await;
1452 assert_eq!(handler.updates().len(), 1);
1453
1454 filter.update(lit(false) as _).unwrap();
1455 handler.wait_for_update_count(2).await;
1456 tokio::time::sleep(Duration::from_millis(50)).await;
1457 assert_eq!(handler.updates().len(), 2);
1458
1459 drop(lease);
1460 handler.wait_for_unregister_count(1).await;
1461 wait_for_registry_drop(registry_weak).await;
1462 }
1463
1464 #[tokio::test]
1465 async fn fanout_task_resends_complete_snapshot_to_late_subscriber() {
1466 let query_id = test_query_id(7);
1467 let manager = Arc::new(DynFilterRegistryManager::default());
1468 let lease = manager.acquire_lease(query_id);
1469 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1470 let filter = test_dyn_filter(&["host"]);
1471 let filter_id = test_filter_id(1);
1472 let _ = lease
1473 .registry()
1474 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1475 let first_subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1476 assert_eq!(
1477 lease
1478 .registry()
1479 .register_subscriber(&filter_id, first_subscriber.clone()),
1480 SubscriberRegistration::Added
1481 );
1482
1483 let handler = Arc::new(RecordingRegionQueryHandler::default());
1484 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1485 handler.wait_for_update_count(1).await;
1486
1487 filter.mark_complete();
1488 handler.wait_for_update_count(2).await;
1489 assert!(handler.updates()[1].is_complete);
1490
1491 let late_subscriber = Subscriber::new(RegionId::new(1024, 8), test_target(1));
1492 assert_eq!(
1493 lease
1494 .registry()
1495 .register_subscriber(&filter_id, late_subscriber.clone()),
1496 SubscriberRegistration::Added
1497 );
1498
1499 handler.wait_for_update_count(4).await;
1500 let updates = handler.updates();
1501 assert!(
1502 updates[2..]
1503 .iter()
1504 .any(|update| update.target == first_subscriber.target().clone()
1505 && update.is_complete)
1506 );
1507 assert!(
1508 updates[2..]
1509 .iter()
1510 .any(|update| update.target == late_subscriber.target().clone()
1511 && update.is_complete)
1512 );
1513
1514 drop(lease);
1515 handler.wait_for_unregister_count(1).await;
1516 wait_for_registry_drop(registry_weak).await;
1517 }
1518
1519 #[tokio::test]
1520 async fn fanout_task_unregisters_when_producer_filter_is_dropped() {
1521 let query_id = test_query_id(8);
1522 let manager = Arc::new(DynFilterRegistryManager::default());
1523 let lease = manager.acquire_lease(query_id);
1524 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1525 let filter = test_dyn_filter(&["host"]);
1526 let filter_id = test_filter_id(1);
1527 let _ = lease
1528 .registry()
1529 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1530 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1531 assert_eq!(
1532 lease
1533 .registry()
1534 .register_subscriber(&filter_id, subscriber.clone()),
1535 SubscriberRegistration::Added
1536 );
1537
1538 let handler = Arc::new(RecordingRegionQueryHandler::default());
1539 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1540 handler.wait_for_update_count(1).await;
1541
1542 drop(filter);
1543 handler.wait_for_unregister_count(1).await;
1544 let unregisters = handler.unregisters();
1545 assert_eq!(&unregisters[0].target, subscriber.target());
1546 assert_eq!(unregisters[0].filter_id, filter_id.to_string());
1547
1548 drop(lease);
1549 wait_for_registry_drop(registry_weak).await;
1550 }
1551
1552 #[tokio::test]
1553 async fn reconcile_tick_catches_update_while_fanout_is_in_flight() {
1554 let query_id = test_query_id(4);
1555 let manager = Arc::new(DynFilterRegistryManager::default());
1556 let lease = manager.acquire_lease(query_id);
1557 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1558 let filter = test_dyn_filter(&["host"]);
1559 let filter_id = test_filter_id(1);
1560 let _ = lease
1561 .registry()
1562 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1563 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1564 assert_eq!(
1565 lease
1566 .registry()
1567 .register_subscriber(&filter_id, subscriber.clone()),
1568 SubscriberRegistration::Added
1569 );
1570
1571 let handler = Arc::new(RecordingRegionQueryHandler::default());
1572 handler.block_next_update();
1573 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1574
1575 handler.wait_for_blocked_update().await;
1576 let initial_generation = handler.updates()[0].generation;
1577
1578 filter.update(lit(false) as _).unwrap();
1580 handler.release_blocked_update();
1581
1582 handler.wait_for_update_count(2).await;
1583 let updates = handler.updates();
1584 assert!(updates[1].generation > initial_generation);
1585 assert_eq!(&updates[1].target, subscriber.target());
1586 assert_eq!(updates[1].filter_id, filter_id.to_string());
1587
1588 drop(lease);
1589 handler.wait_for_unregister_count(1).await;
1590 wait_for_registry_drop(registry_weak).await;
1591 }
1592
1593 #[tokio::test]
1594 async fn fanout_task_unregisters_after_lifecycle_close_during_blocked_update() {
1595 let query_id = test_query_id(5);
1596 let manager = Arc::new(DynFilterRegistryManager::default());
1597 let lease = manager.acquire_lease(query_id);
1598 let registry_weak = Arc::downgrade(lease.registry.as_ref().unwrap());
1599 let filter = test_dyn_filter(&["host"]);
1600 let filter_id = test_filter_id(1);
1601 let _ = lease
1602 .registry()
1603 .register_remote_dyn_filter(filter_id.clone(), filter.clone());
1604 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1605 assert_eq!(
1606 lease
1607 .registry()
1608 .register_subscriber(&filter_id, subscriber.clone()),
1609 SubscriberRegistration::Added
1610 );
1611
1612 let handler = Arc::new(RecordingRegionQueryHandler::default());
1613 handler.block_next_update();
1614 lease.ensure_fanout_task(handler.clone() as RegionQueryHandlerRef);
1615
1616 handler.wait_for_blocked_update().await;
1617 drop(lease);
1618
1619 handler.wait_for_unregister_count(1).await;
1620 let unregisters = handler.unregisters();
1621 assert_eq!(&unregisters[0].target, subscriber.target());
1622 assert_eq!(unregisters[0].filter_id, filter_id.to_string());
1623 wait_for_registry_drop(registry_weak).await;
1624 }
1625
1626 #[tokio::test]
1627 async fn update_timeout_does_not_stop_fanout_for_other_subscribers() {
1628 let query_id = test_query_id(9);
1629 let registry = QueryDynFilterRegistry::new(query_id);
1630 let filter = test_dyn_filter(&["host"]);
1631 let filter_id = test_filter_id(1);
1632 let entry = match registry.register_remote_dyn_filter(filter_id.clone(), filter.clone()) {
1633 EntryRegistration::Inserted(entry) => entry,
1634 other => panic!("unexpected registration result: {other:?}"),
1635 };
1636 let first_subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1637 let second_subscriber = Subscriber::new(RegionId::new(1024, 8), test_target(2));
1638 assert_eq!(
1639 registry.register_subscriber(&filter_id, first_subscriber.clone()),
1640 SubscriberRegistration::Added
1641 );
1642 assert_eq!(
1643 registry.register_subscriber(&filter_id, second_subscriber.clone()),
1644 SubscriberRegistration::Added
1645 );
1646
1647 let handler = Arc::new(RecordingRegionQueryHandler::default());
1648 let handler_ref = handler.clone() as RegionQueryHandlerRef;
1649 let mut lifecycle_rx = registry.lifecycle_tx.subscribe();
1650 handler.block_next_update();
1651 assert!(
1652 fanout_snapshot_for_query(
1653 query_id,
1654 &handler_ref,
1655 &entry,
1656 filter.as_ref(),
1657 false,
1658 &mut lifecycle_rx,
1659 Duration::from_millis(100),
1660 )
1661 .await
1662 );
1663
1664 handler.wait_for_blocked_update().await;
1665 handler.wait_for_update_count(2).await;
1668
1669 let initial_updates = handler.updates();
1670 assert_eq!(
1671 initial_updates.len(),
1672 2,
1673 "the healthy subscriber must still receive the update after another subscriber times out"
1674 );
1675 assert!(
1676 initial_updates
1677 .iter()
1678 .any(|update| update.target == first_subscriber.target().clone())
1679 );
1680 assert!(
1681 initial_updates
1682 .iter()
1683 .any(|update| update.target == second_subscriber.target().clone())
1684 );
1685
1686 filter.update(lit(false) as _).unwrap();
1687 assert!(
1688 fanout_snapshot_for_query(
1689 query_id,
1690 &handler_ref,
1691 &entry,
1692 filter.as_ref(),
1693 false,
1694 &mut lifecycle_rx,
1695 Duration::from_millis(100),
1696 )
1697 .await
1698 );
1699 handler.wait_for_update_count(4).await;
1700 let updates = handler.updates();
1701 assert!(
1702 updates[2..]
1703 .iter()
1704 .any(|update| update.target == first_subscriber.target().clone())
1705 );
1706 assert!(
1707 updates[2..]
1708 .iter()
1709 .any(|update| update.target == second_subscriber.target().clone())
1710 );
1711
1712 registry.unregister_all_once(&handler_ref).await;
1713 handler.wait_for_unregister_count(1).await;
1714 }
1715
1716 #[tokio::test]
1717 async fn unregister_fanout_is_idempotent() {
1718 let query_id = test_query_id(2);
1719 let registry = QueryDynFilterRegistry::new(query_id);
1720 let filter = test_dyn_filter(&["host"]);
1721 let filter_id = test_filter_id(1);
1722 let _ = registry.register_remote_dyn_filter(filter_id.clone(), filter);
1723 let subscriber = Subscriber::new(RegionId::new(1024, 7), test_target(1));
1724 assert_eq!(
1725 registry.register_subscriber(&filter_id, subscriber.clone()),
1726 SubscriberRegistration::Added
1727 );
1728
1729 let handler = Arc::new(RecordingRegionQueryHandler::default());
1730 let handler_ref = handler.clone() as RegionQueryHandlerRef;
1731
1732 registry.unregister_all_once(&handler_ref).await;
1733 registry.unregister_all_once(&handler_ref).await;
1734
1735 let unregisters = handler.unregisters();
1736 assert_eq!(unregisters.len(), 1);
1737 assert_eq!(&unregisters[0].target, subscriber.target());
1738 assert_eq!(unregisters[0].query_id, query_id.to_string());
1739 assert_eq!(unregisters[0].filter_id, filter_id.to_string());
1740 }
1741}