pub trait Detach: Manage {
type Parked: Send + 'static;
// Required methods
fn detach(conn: Self::Connection) -> Option<Self::Parked>;
fn attach(
parked: Self::Parked,
) -> impl Future<Output = Result<Self::Connection, Self::Error>>;
}Expand description
Opt-in marker for connections that can legally change threads.
Implementing this lets a connection be parked in the cross-thread
Reservoir, so an idle connection on one compio thread
can be picked up by a busy one instead of sitting unused.
§Only idle connections, never one with an operation in flight
Moving a handle between drivers is sound only when nothing is still
submitted against it. The pool upholds half of that for you: a connection
reaches detach only after its Pooled
guard has been dropped, and a checkout cancelled mid-operation is poisoned
and destroyed rather than parked. detach returning
Option is the other half — the implementation gets to check, rather
than trust, that the handle is genuinely unshared.
§Platform reality
Whether this is sound depends on the driver, and the answer differs by OS:
- io_uring and poll (Unix) —
Driver::attachis a no-op. The fd table is process-wide and any thread may submit ops on any fd, so moving a connection between compio threads costs nothing.Detachis safe here. - IOCP (Windows) —
attachcallsCreateIoCompletionPort, and compio documents that “a handle can and only can attach once to one driver”. A socket bound to thread A’s port keeps delivering completions to thread A’s port forever. Do not implementDetachon Windows for types backed by an IOCP handle.
Beyond the fd itself, everything you carry in Parked
must be Send: buffers, TLS session state, prepared-statement caches. A
connection whose state includes an Rc cannot implement this trait, which
is precisely the point of separating it from Manage.
Required Associated Types§
Required Methods§
Sourcefn detach(conn: Self::Connection) -> Option<Self::Parked>
fn detach(conn: Self::Connection) -> Option<Self::Parked>
Converts a connection into its thread-portable form.
Returns None when the connection cannot be made portable — in
practice, when an IO operation still holds a reference to the
underlying handle. The connection is consumed either way: None
means it has been dropped, and the pool accounts for it as closed
rather than parked, then dials a replacement.
With compio, the check is
SharedFd::try_unwrap, which
succeeds exactly when no submission still references the fd. See
examples/steal.rs.
Sourcefn attach(
parked: Self::Parked,
) -> impl Future<Output = Result<Self::Connection, Self::Error>>
fn attach( parked: Self::Parked, ) -> impl Future<Output = Result<Self::Connection, Self::Error>>
Rebuilds a connection on the current thread.
This is where the socket is re-wrapped in this thread’s runtime —
TcpStream::from_std, or a from_raw_fd constructor, depending on the
compio version. Under io_uring and poll that is bookkeeping only; the
fd table is process-wide.
Returning Err drops the parked connection; the caller falls back to
opening a fresh one.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".