Expand description
A bb8-style connection pool for compio on Linux io_uring.
You build one Pool — the manager plus a handful of Builder knobs —
then clone that handle onto each thread of your own thread-per-core runtime.
On every thread you call Pool::local once to get that thread’s
LocalPool, and LocalPool::get to lease a connection. The pool is the
product; spawning threads, pinning them and running an accept loop are yours.
§Why it is shaped this way
A compio connection is bound to the io_uring ring of the thread that
opened it: its buffers are registered with that ring and its completions are
delivered there. It cannot be used from another thread. So, unlike bb8 on
tokio, the pool of connections cannot be a single shared, work-stealing
store. What is shared is only the blueprint:
Pool—Send + Sync + Clone. The manager and the configuration, behind oneArc. Cloning is anArcbump. This is the only thing that crosses threads.LocalPool—!Send, one per thread. The idle connections and the slot count, allRc/Cell, no lock, no atom. The compiler keeps it, and the ring-bound connections it holds, on its own thread.
The parts of bb8 that make sense per thread are here — max_size, idle and
lifetime timeouts, test_on_check_out, min_idle warm-up — sized per
thread, not per process.
§Running it in production
Three things a long-lived server needs are built on the same split:
- Metrics. Each
LocalPoolkeeps its own counters and registers them with thePool.LocalPool::state/LocalPool::statisticsread one thread’s lock-free;Pool::state/Pool::statisticssum every thread’s for a process-wideStateandStatisticsto feed a metrics endpoint. - Maintenance. Expiry is lazy, so a quiet pool would hold dead backend
connections open. Call
LocalPool::maintainon a timer on each worker — it reaps expired idle connections (LocalPool::reap) and tops back up tomin_idle— since thread-per-core has no shared reaper thread. - Shutdown.
Pool::closemakes every thread’sgetfail withRunError::Closedand stops recycling;LocalPool::cleardrains a thread’s idle connections for a prompt drain.
§Quickstart
Define a manager, build the pool, and use it from a compio task:
use std::io;
use compio_pool::{ManageConnection, Pool};
/// A pool of reusable 16 KiB scratch buffers. A real manager would open a
/// backend connection (Redis, Postgres, an upstream socket) in `connect`.
struct Buffers;
impl ManageConnection for Buffers {
type Connection = Vec<u8>;
type Error = io::Error;
async fn connect(&self) -> io::Result<Vec<u8>> {
Ok(Vec::with_capacity(16 * 1024))
}
async fn is_valid(&self, _buf: &mut Vec<u8>) -> io::Result<()> {
Ok(())
}
fn has_broken(&self, _buf: &mut Vec<u8>) -> bool {
false
}
}
// Build once; `Pool` is `Send + Clone`, so hand a clone to each thread.
let pool = Pool::builder().max_size(1024).build(Buffers);
// On each compio thread you spawn (see `examples/echo.rs` for the full
// pinned, SO_REUSEPORT thread-per-core setup):
let local = pool.local(); // this thread's own pool, `!Send`
let mut buf = local.get().await?; // PooledConnection, returned on drop
buf.clear();The crate also ships the two helpers that building your own thread-per-core
loop needs: cpu for core enumeration and pinning, and
listener::bind_reuseport for a shared-address SO_REUSEPORT socket.
§Platform
Linux is the only supported target: SO_REUSEPORT load balancing and
io_uring are Linux semantics. The crate type-checks on other Unixes so
editors work, but nothing is tested there.
Re-exports§
pub use builder::Builder;pub use listener::bind_reuseport;pub use manage::ManageConnection;pub use manage::RunError;pub use pool::LocalPool;pub use pool::Pool;pub use pool::PooledConnection;pub use pool::State;pub use pool::Statistics;
Modules§
- builder
- Build a
Poolfrom a manager and a handful of knobs — the bb8Builder, minus the settings that only make sense for a single shared pool. - cpu
- Core enumeration and thread pinning — the helpers you need to stand up your
own thread-per-core runtime around a
Pool. - listener
- A
SO_REUSEPORTlistener helper, for building your own thread-per-core accept loop around aPool. - manage
- The manager trait and the error
getcan return — the bb8 vocabulary, adapted for a completion runtime where a connection never leaves the thread it was opened on. - pool
- The pool: a
Sendblueprint you build once and clone onto every thread, and the strictly thread-local pool it stamps out on each.
Structs§
- CoreId
- This represents a CPU core.