Skip to main content

qinterface/
manager.rs

1use std::{
2    any::Any,
3    fmt::Debug,
4    future::Future,
5    io, mem,
6    net::SocketAddr,
7    ops::{Deref, DerefMut},
8    sync::{Arc, OnceLock},
9    task::{Context, Poll, ready},
10};
11
12use bytes::BytesMut;
13use dashmap::{DashMap, Entry};
14use futures::FutureExt;
15use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
16use qbase::{
17    net::route,
18    util::{UniqueId, UniqueIdGenerator},
19};
20use tokio::sync::SetOnce;
21use tracing::Instrument as _;
22
23use crate::{
24    BindInterface, Interface, RebindedError, WeakBindInterface,
25    bind_uri::BindUri,
26    component::{Component, Components},
27    io::{IO, IoExt, ProductIO},
28};
29
30/// Global [`IO`] manager that manages the lifecycle of all interfaces.
31///
32/// Calling the [`InterfaceManager::bind`] method with a [`BindUri`] returns a [`BindInterface`], primarily used for listening on addresses.
33/// As long as [`BindInterface`] instances exist, the corresponding [`IO`] for that [`BindUri`] won't be automatically released.
34///
35/// For actual data transmission, you need [`Interface`], which can be obtained via [`InterfaceManager::borrow`] or [`BindInterface::borrow`].
36/// Like [`BindInterface`], it keeps the [`IO`] alive, but with one key difference: once a rebind occurs,
37/// any previous [`Interface`] for that [`BindUri`] becomes invalid, and attempting to send or receive packets
38/// will result in [`RebindedError] errors.
39#[derive(Default, Debug)]
40pub struct InterfaceManager {
41    interfaces: DashMap<BindUri, InterfaceEntry>,
42    bind_id_generator: UniqueIdGenerator,
43}
44
45#[derive(Debug)]
46struct InterfaceEntry {
47    weak_iface: WeakBindInterface,
48    dropped: Arc<SetOnce<()>>,
49}
50
51impl InterfaceEntry {
52    fn is_dropped(&self) -> bool {
53        self.dropped.get().is_some()
54    }
55
56    fn dropped(&self) -> impl Future<Output = ()> + use<> {
57        let dropped = self.dropped.clone();
58        async move {
59            dropped.wait().await;
60        }
61    }
62}
63
64impl InterfaceManager {
65    #[inline]
66    pub fn global() -> &'static Arc<Self> {
67        static GLOBAL: OnceLock<Arc<InterfaceManager>> = OnceLock::new();
68        GLOBAL.get_or_init(Arc::default)
69    }
70
71    #[inline]
72    pub fn new() -> Self {
73        Self::default()
74    }
75
76    fn new_binding(
77        self: &Arc<Self>,
78        entry: Entry<BindUri, InterfaceEntry>,
79        factory: Arc<dyn ProductIO>,
80    ) -> BindInterface {
81        let context = InterfaceContext {
82            factory: factory.clone(),
83            binding: RwLock::new(Binding::new(
84                factory.bind(entry.key().clone()),
85                self.bind_id_generator.generate(),
86            )),
87            dropped: Arc::new(SetOnce::new()),
88            ifaces: self.clone(),
89            components: RwLock::new(Components::default()),
90        };
91        let dropped = context.dropped.clone();
92        let iface = BindInterface::new(context);
93        let weak_iface = iface.downgrade();
94
95        entry.insert(InterfaceEntry {
96            weak_iface,
97            dropped,
98        });
99
100        iface
101    }
102
103    pub async fn bind(
104        self: &Arc<Self>,
105        bind_uri: BindUri,
106        factory: Arc<dyn ProductIO>,
107    ) -> BindInterface {
108        // TODO: error: rebind with difference factory
109        loop {
110            match self.interfaces.entry(bind_uri.clone()) {
111                // (1) new binding: context closed but not yet removed
112                Entry::Occupied(entry) if entry.get().is_dropped() => {
113                    return self.new_binding(Entry::Occupied(entry), factory);
114                }
115                // (2) new binding: no existing context
116                Entry::Vacant(entry) => {
117                    return self.new_binding(Entry::Vacant(entry), factory);
118                }
119                // try reuse existing binding
120                Entry::Occupied(entry) => match entry.get().weak_iface.upgrade() {
121                    // (3) reuse existing binding
122                    Ok(iface) => {
123                        if iface.borrow().bound_addr().is_ok() {
124                            return iface.clone();
125                        }
126
127                        tracing::debug!(
128                            target: "interface",
129                            bind_uri = %bind_uri,
130                            "replacing closed interface binding during bind"
131                        );
132                        drop(iface);
133                        return self.new_binding(Entry::Occupied(entry), factory);
134                    }
135                    // (4) no existing binding: close context and retry
136                    Err(..) => {
137                        let dropped_future = entry.get().dropped();
138                        drop(entry);
139                        dropped_future.await;
140                    }
141                },
142            }
143        }
144    }
145
146    #[inline]
147    pub fn borrow(&self, bind_uri: &BindUri) -> Option<Interface> {
148        self.interfaces
149            .get(bind_uri)
150            .and_then(|entry| Some(entry.weak_iface.upgrade().ok()?.borrow()))
151    }
152
153    #[inline]
154    pub fn get(&self, bind_uri: &BindUri) -> Option<BindInterface> {
155        self.interfaces
156            .get(bind_uri)
157            .and_then(|entry| entry.weak_iface.upgrade().ok())
158    }
159
160    #[inline]
161    pub fn unbind(self: &Arc<Self>, bind_uri: BindUri) -> impl Future<Output = ()> + Send + use<> {
162        let Entry::Occupied(entry) = self.interfaces.entry(bind_uri) else {
163            return std::future::ready(()).right_future();
164        };
165
166        match entry.get().weak_iface.upgrade() {
167            Ok(bind_iface) => {
168                let drop_future = bind_iface.context.as_ref().drop();
169                spawn_on_drop::SpawnOnDrop::new(Box::pin(drop_future)).left_future()
170            }
171            // Dropping by InterfaceContext::Drop
172            Err(..) => entry.get().dropped().right_future(),
173        }
174        .left_future()
175    }
176}
177
178mod spawn_on_drop {
179    use std::{
180        future::Future,
181        pin::Pin,
182        task::{Context, Poll, ready},
183    };
184
185    use tracing::Instrument;
186
187    pub(crate) struct SpawnOnDrop<F: Future<Output: Send + 'static> + Unpin + Send + 'static> {
188        pub(crate) future: Option<F>,
189    }
190
191    impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> SpawnOnDrop<F> {
192        pub(crate) fn new(future: F) -> Self {
193            Self {
194                future: Some(future),
195            }
196        }
197    }
198
199    impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> Future for SpawnOnDrop<F> {
200        type Output = F::Output;
201
202        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
203            match self.as_mut().get_mut().future.as_mut() {
204                Some(future) => {
205                    let output = ready!(Pin::new(future).poll(cx));
206                    self.future = None;
207                    Poll::Ready(output)
208                }
209                None => panic!("future polled after completion"),
210            }
211        }
212    }
213
214    impl<F: Future<Output: Send + 'static> + Unpin + Send + 'static> Drop for SpawnOnDrop<F> {
215        fn drop(&mut self) {
216            if let Some(future) = self.future.take() {
217                // Best-effort: schedule the must-complete future before it is dropped.
218                tokio::spawn(future.in_current_span());
219            }
220        }
221    }
222}
223
224struct Binding {
225    io: Box<dyn IO>,
226    id: UniqueId,
227    span: tracing::Span,
228}
229
230impl Binding {
231    fn new(io: Box<dyn IO>, id: UniqueId) -> Self {
232        let bind_uri = io.bind_uri();
233        let span = tracing::debug_span!(
234            target: "interface",
235            parent: None,
236            "interface",
237            %bind_uri,
238            bind_id = usize::from(id),
239        );
240        Self { io, id, span }
241    }
242}
243
244pub struct InterfaceContext {
245    factory: Arc<dyn ProductIO>,
246    binding: RwLock<Binding>,
247    // shared with [InterfaceEntry]
248    dropped: Arc<SetOnce<()>>,
249    ifaces: Arc<InterfaceManager>,
250    components: RwLock<Components>,
251}
252
253impl InterfaceContext {
254    fn binding(&self) -> RwLockReadGuard<'_, Binding> {
255        self.binding.read_recursive()
256    }
257
258    fn binding_mut(&self) -> RwLockWriteGuard<'_, Binding> {
259        self.binding.write()
260    }
261
262    pub fn bind_id(&self) -> UniqueId {
263        self.binding().id
264    }
265
266    fn with_io<T>(&self, f: impl FnOnce(&dyn IO) -> T) -> T {
267        let binding = self.binding();
268        let _guard = binding.span.enter();
269        f(binding.io.as_ref())
270    }
271
272    pub(crate) fn with_bind_io<T>(
273        &self,
274        bind_id: UniqueId,
275        f: impl FnOnce(&dyn IO) -> T,
276    ) -> Result<T, RebindedError> {
277        let binding = self.binding();
278        if binding.id != bind_id {
279            return Err(RebindedError);
280        }
281        let _guard = binding.span.enter();
282        Ok(f(binding.io.as_ref()))
283    }
284
285    fn components(&self) -> RwLockReadGuard<'_, Components> {
286        self.components.read_recursive()
287    }
288
289    fn components_mut(&self) -> RwLockWriteGuard<'_, Components> {
290        self.components.write()
291    }
292
293    pub fn poll_close(&self, cx: &mut Context) -> Poll<io::Result<()>> {
294        let (mut binding, components) = (self.binding_mut(), self.components());
295        for (.., component) in &components.map {
296            ready!(component.poll_shutdown(cx));
297        }
298        binding.io.poll_close(cx)
299    }
300}
301
302impl Debug for InterfaceContext {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        f.debug_struct("Interface")
305            .field("bind_uri", &self.binding().io.bind_uri())
306            .finish()
307    }
308}
309
310impl BindInterface {
311    pub fn poll_rebind(&self, cx: &mut Context<'_>) -> Poll<()> {
312        let context = self.context.as_ref();
313
314        // 降级binding锁
315        // A: rebind, reinit
316        // B:                rebind, reinit
317
318        // 释放binding锁
319        // A: lock(B), lock(C), rebind, release(B), reinit, release(C)
320        // B:                                      lock(B),             lock(C), rebind, reinit
321
322        // hold read lock to prevent subsequent rebind, avoid compoents seeing inconsistent state
323        let (new_bind_id, components, span) = {
324            let mut binding = context.binding_mut();
325            let components = context.components();
326
327            ready!(context.factory.poll_rebind(cx, &mut binding.io));
328            binding.id = context.ifaces.bind_id_generator.generate();
329            binding.span = tracing::debug_span!(
330                target: "interface",
331                parent: None,
332                "interface",
333                bind_uri = %binding.io.bind_uri(),
334                bind_id = usize::from(binding.id),
335            );
336            (binding.id, components, binding.span.clone())
337        };
338
339        let iface = Interface {
340            bind_id: new_bind_id,
341            bind_iface: self.clone(),
342        };
343        let _guard = span.enter();
344        for (.., component) in &components.map {
345            component.reinit(&iface);
346        }
347        Poll::Ready(())
348    }
349
350    pub fn insert_component_with<C: Component>(&self, init: impl FnOnce(&Interface) -> C) {
351        self.with_components_mut(|components, iface| {
352            components.init_with(|| init(iface));
353        });
354    }
355
356    pub fn with_components<T>(&self, f: impl FnOnce(&Components, &Interface) -> T) -> T {
357        let context = self.context.as_ref();
358        let (binding, components) = (context.binding(), context.components());
359        let _guard = binding.span.enter();
360
361        let iface = Interface {
362            bind_id: binding.id,
363            bind_iface: self.clone(),
364        };
365        f(components.deref(), &iface)
366    }
367
368    pub fn with_components_mut<T>(&self, f: impl FnOnce(&mut Components, &Interface) -> T) -> T {
369        let context = self.context.as_ref();
370        let (binding, mut components) = (context.binding(), context.components_mut());
371        let _guard = binding.span.enter();
372
373        let iface = Interface {
374            bind_id: binding.id,
375            bind_iface: self.clone(),
376        };
377        f(components.deref_mut(), &iface)
378    }
379}
380
381impl Interface {
382    pub fn with_component<C: Component, T>(
383        &self,
384        f: impl FnOnce(&C) -> T,
385    ) -> Result<Option<T>, RebindedError> {
386        let context = self.bind_iface.context.as_ref();
387        let (binding, components) = (context.binding(), context.components());
388
389        if self.bind_id != binding.id {
390            return Err(RebindedError);
391        }
392
393        let _guard = binding.span.enter();
394        Ok(components.with(f))
395    }
396
397    pub fn with_components<T>(&self, f: impl FnOnce(&Components) -> T) -> Result<T, RebindedError> {
398        let context = self.bind_iface.context.as_ref();
399        let (binding, components) = (context.binding(), context.components());
400
401        if self.bind_id != binding.id {
402            return Err(RebindedError);
403        }
404
405        let _guard = binding.span.enter();
406        Ok(f(components.deref()))
407    }
408
409    pub fn get_component<C: Component + Clone>(&self) -> Result<Option<C>, RebindedError> {
410        self.with_component(C::clone)
411    }
412}
413
414impl IO for InterfaceContext {
415    fn bind_uri(&self) -> BindUri {
416        self.binding().io.bind_uri()
417    }
418
419    fn bound_addr(&self) -> io::Result<SocketAddr> {
420        self.with_io(|io| io.bound_addr())
421    }
422
423    fn max_segment_size(&self) -> io::Result<usize> {
424        self.with_io(|io| io.max_segment_size())
425    }
426
427    fn max_segments(&self) -> io::Result<usize> {
428        self.with_io(|io| io.max_segments())
429    }
430
431    fn poll_send(
432        &self,
433        cx: &mut Context,
434        pkts: &[io::IoSlice],
435        route: route::Route,
436    ) -> Poll<io::Result<usize>> {
437        self.with_io(|io| io.poll_send(cx, pkts, route))
438    }
439
440    fn poll_recv(
441        &self,
442        cx: &mut Context,
443        pkts: &mut [BytesMut],
444        route: &mut [route::Route],
445    ) -> Poll<io::Result<usize>> {
446        self.with_io(|io| io.poll_recv(cx, pkts, route))
447    }
448
449    fn poll_close(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
450        InterfaceContext::poll_close(self, cx)
451    }
452}
453
454mod dropping_io {
455    use thiserror::Error;
456
457    use super::*;
458
459    #[derive(Debug, Clone, Error)]
460    #[error("QuicIO is dropping and cannot be used anymore, you should never see this error")]
461    pub(crate) struct DroppingIO {
462        pub(crate) bind_uri: BindUri,
463    }
464
465    impl DroppingIO {
466        pub(crate) fn to_io_error(&self) -> io::Error {
467            io::Error::new(io::ErrorKind::NotConnected, self.clone())
468        }
469    }
470
471    impl From<DroppingIO> for io::Error {
472        fn from(error: DroppingIO) -> Self {
473            error.to_io_error()
474        }
475    }
476
477    impl IO for DroppingIO {
478        fn bind_uri(&self) -> BindUri {
479            self.bind_uri.clone()
480        }
481
482        fn bound_addr(&self) -> io::Result<SocketAddr> {
483            Err(self.to_io_error())
484        }
485
486        fn max_segment_size(&self) -> io::Result<usize> {
487            Err(self.to_io_error())
488        }
489
490        fn max_segments(&self) -> io::Result<usize> {
491            Err(self.to_io_error())
492        }
493
494        fn poll_send(
495            &self,
496            _: &mut Context,
497            _: &[io::IoSlice],
498            _: route::Route,
499        ) -> Poll<io::Result<usize>> {
500            Poll::Ready(Err(self.to_io_error()))
501        }
502
503        fn poll_recv(
504            &self,
505            _: &mut Context,
506            _: &mut [BytesMut],
507            _: &mut [route::Route],
508        ) -> Poll<io::Result<usize>> {
509            Poll::Ready(Err(self.to_io_error()))
510        }
511
512        fn poll_close(&mut self, _: &mut Context) -> Poll<io::Result<()>> {
513            Poll::Ready(Ok(()))
514        }
515    }
516}
517
518impl Binding {
519    pub fn is_dropping(&self) -> bool {
520        (self.io.as_ref() as &dyn Any).is::<dropping_io::DroppingIO>()
521    }
522
523    pub fn take_io(&mut self) -> Option<Box<dyn IO>> {
524        if self.is_dropping() {
525            return None;
526        }
527        let bind_uri = self.io.bind_uri();
528        let dropping_io = Box::new(dropping_io::DroppingIO { bind_uri });
529        Some(mem::replace(&mut self.io, dropping_io))
530    }
531}
532
533impl InterfaceContext {
534    fn drop(&self) -> impl Future<Output = ()> + Send + use<> {
535        let dropped = self.dropped.clone();
536        let Some(mut io) = self.binding_mut().take_io() else {
537            return std::future::ready(()).right_future();
538        };
539
540        let ifaces = self.ifaces.clone();
541        let bind_uri = io.bind_uri();
542        let components = mem::take(self.components_mut().deref_mut());
543
544        async move {
545            for (_, component) in components.map {
546                _ = core::future::poll_fn(|cx| component.poll_shutdown(cx)).await;
547            }
548            _ = io.close().await;
549
550            dropped.set(()).expect("duplicated drop, this is a bug");
551            tokio::task::spawn_blocking(move || {
552                ifaces
553                    .interfaces
554                    .remove_if(&bind_uri, |_, entry| entry.is_dropped());
555            });
556        }
557        .left_future()
558    }
559}
560
561impl Drop for InterfaceContext {
562    fn drop(&mut self) {
563        if !{ self.binding().is_dropping() } {
564            // Best-effort: schedule async cleanup before the context is dropped.
565            tokio::spawn(InterfaceContext::drop(self).in_current_span());
566        }
567    }
568}
569
570#[cfg(test)]
571mod tests {
572    use std::{
573        sync::{
574            Arc,
575            atomic::{AtomicUsize, Ordering},
576        },
577        task::{Context, Poll},
578    };
579
580    use futures::task::noop_waker_ref;
581
582    use super::*;
583    use crate::{
584        component::Component,
585        io::{IO, ProductIO},
586    };
587
588    #[derive(Debug)]
589    struct TestComponent {
590        shutdown_calls: Arc<AtomicUsize>,
591    }
592
593    impl Component for TestComponent {
594        fn poll_shutdown(&self, _cx: &mut Context<'_>) -> Poll<()> {
595            self.shutdown_calls.fetch_add(1, Ordering::SeqCst);
596            Poll::Ready(())
597        }
598
599        fn reinit(&self, _iface: &crate::Interface) {}
600    }
601
602    #[derive(Debug)]
603    struct TestIo {
604        bind_uri: BindUri,
605        close_calls: Arc<AtomicUsize>,
606    }
607
608    impl IO for TestIo {
609        fn bind_uri(&self) -> BindUri {
610            self.bind_uri.clone()
611        }
612
613        fn bound_addr(&self) -> io::Result<SocketAddr> {
614            Err(io::Error::new(io::ErrorKind::Unsupported, "not needed"))
615        }
616
617        fn max_segment_size(&self) -> io::Result<usize> {
618            Ok(1200)
619        }
620
621        fn max_segments(&self) -> io::Result<usize> {
622            Ok(1)
623        }
624
625        fn poll_send(
626            &self,
627            _cx: &mut Context,
628            _pkts: &[io::IoSlice],
629            _route: route::Route,
630        ) -> Poll<io::Result<usize>> {
631            Poll::Ready(Ok(0))
632        }
633
634        fn poll_recv(
635            &self,
636            _cx: &mut Context,
637            _pkts: &mut [BytesMut],
638            _route: &mut [route::Route],
639        ) -> Poll<io::Result<usize>> {
640            Poll::Pending
641        }
642
643        fn poll_close(&mut self, _cx: &mut Context) -> Poll<io::Result<()>> {
644            self.close_calls.fetch_add(1, Ordering::SeqCst);
645            Poll::Ready(Ok(()))
646        }
647    }
648
649    #[derive(Debug)]
650    struct TestFactory {
651        close_calls: Arc<AtomicUsize>,
652    }
653
654    impl ProductIO for TestFactory {
655        fn bind(&self, bind_uri: BindUri) -> Box<dyn IO> {
656            Box::new(TestIo {
657                bind_uri,
658                close_calls: self.close_calls.clone(),
659            })
660        }
661    }
662
663    #[test]
664    fn binding_take_io_is_idempotent_and_switches_to_dropping_io() {
665        let close_calls = Arc::new(AtomicUsize::new(0));
666        let bind_uri: BindUri = "inet://127.0.0.1:0".into();
667
668        let mut binding = Binding::new(
669            Box::new(TestIo {
670                bind_uri: bind_uri.clone(),
671                close_calls: close_calls.clone(),
672            }),
673            UniqueIdGenerator::new().generate(),
674        );
675
676        let first = binding.take_io();
677        assert!(first.is_some());
678        assert!(binding.is_dropping());
679
680        let second = binding.take_io();
681        assert!(second.is_none());
682
683        // Ensure the original IO wasn't closed by take_io itself.
684        assert_eq!(close_calls.load(Ordering::SeqCst), 0);
685    }
686
687    #[test]
688    fn poll_close_shuts_down_components_before_io_close() {
689        let shutdown_calls = Arc::new(AtomicUsize::new(0));
690        let close_calls = Arc::new(AtomicUsize::new(0));
691
692        let bind_uri: BindUri = "inet://127.0.0.1:0".into();
693        let mut components = Components::new();
694        components.init_with(|| TestComponent {
695            shutdown_calls: shutdown_calls.clone(),
696        });
697
698        let mut cx = Context::from_waker(noop_waker_ref());
699        let ctx = InterfaceContext {
700            factory: Arc::new(TestFactory {
701                close_calls: close_calls.clone(),
702            }),
703            binding: RwLock::new(Binding::new(
704                Box::new(TestIo {
705                    bind_uri,
706                    close_calls: close_calls.clone(),
707                }),
708                UniqueIdGenerator::new().generate(),
709            )),
710            dropped: Arc::new(SetOnce::new()),
711            ifaces: Arc::new(InterfaceManager::new()),
712            components: RwLock::new(components),
713        };
714
715        let r = ctx.poll_close(&mut cx);
716        assert!(matches!(r, Poll::Ready(Ok(()))));
717        assert_eq!(shutdown_calls.load(Ordering::SeqCst), 1);
718        assert_eq!(close_calls.load(Ordering::SeqCst), 1);
719
720        // Prevent Drop from spawning without a runtime.
721        let _ = ctx.binding_mut().take_io();
722    }
723}