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