Skip to main content

Detach

Trait Detach 

Source
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::attach is 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. Detach is safe here.
  • IOCP (Windows) — attach calls CreateIoCompletionPort, 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 implement Detach on 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§

Source

type Parked: Send + 'static

The connection reduced to a form that may cross threads.

Typically an OwnedFd/SharedFd plus whatever protocol state is Send.

Required Methods§

Source

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.

Source

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".

Implementors§