Skip to main content

compio_pool/
manage.rs

1//! The manager trait and the error [`get`](crate::LocalPool::get) can return —
2//! the bb8 vocabulary, adapted for a completion runtime where a connection never
3//! leaves the thread it was opened on.
4
5use std::{error::Error, fmt, future::Future};
6
7/// Teaches a [`Pool`](crate::Pool) how to open and check the connections it
8/// hands out.
9///
10/// One manager is shared — behind an `Arc` — by every thread's
11/// [`LocalPool`](crate::LocalPool), so the manager value itself is `Send + Sync`.
12/// The connections it produces are **not**: each belongs to the `io_uring` ring
13/// of the thread that opened it and must live and die there. That is the one
14/// difference from bb8's `ManageConnection` — [`Connection`](Self::Connection)
15/// carries no `Send` bound, and every future returned here runs on a single
16/// thread.
17pub trait ManageConnection: Send + Sync + 'static {
18    /// The connection this manager opens: a `compio` `TcpStream`, a framed
19    /// client on top of one, a reusable buffer — anything a thread keeps a
20    /// bounded number of. Ring-bound, hence not `Send`.
21    type Connection: 'static;
22
23    /// What [`connect`](Self::connect) and [`is_valid`](Self::is_valid) fail
24    /// with.
25    type Error: Error + 'static;
26
27    /// Open a new connection. Called on the thread whose
28    /// [`LocalPool`](crate::LocalPool) asked for it, inside that thread's runtime,
29    /// so its I/O is submitted to that thread's ring.
30    fn connect(&self) -> impl Future<Output = Result<Self::Connection, Self::Error>>;
31
32    /// Check a connection as it is handed out, when
33    /// [`test_on_check_out`](crate::Builder::test_on_check_out) is set. Returning
34    /// `Err` discards the connection; the pool then opens a fresh one in its
35    /// place.
36    fn is_valid(
37        &self,
38        conn: &mut Self::Connection,
39    ) -> impl Future<Output = Result<(), Self::Error>>;
40
41    /// A synchronous, infallible liveness check run as a connection is returned.
42    /// Returning `true` drops it instead of putting it back on the idle list.
43    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
44}
45
46/// What [`LocalPool::get`](crate::LocalPool::get) returns on failure.
47#[derive(Debug)]
48pub enum RunError<E> {
49    /// The manager failed to open or validate a connection.
50    User(E),
51    /// No connection became available within
52    /// [`connection_timeout`](crate::Builder::connection_timeout).
53    TimedOut,
54    /// The pool was shut down with [`Pool::close`](crate::Pool::close); it hands
55    /// out no more connections.
56    Closed,
57}
58
59impl<E: fmt::Display> fmt::Display for RunError<E> {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            RunError::User(e) => write!(f, "{e}"),
63            RunError::TimedOut => f.write_str("timed out waiting for a pooled connection"),
64            RunError::Closed => f.write_str("the connection pool is closed"),
65        }
66    }
67}
68
69impl<E: Error + 'static> Error for RunError<E> {
70    fn source(&self) -> Option<&(dyn Error + 'static)> {
71        match self {
72            RunError::User(e) => Some(e),
73            RunError::TimedOut | RunError::Closed => None,
74        }
75    }
76}