Skip to main content

Builder

Struct Builder 

Source
pub struct Builder<M: ManageConnection> { /* private fields */ }
Expand description

Configures and builds a Pool.

Every size here is per thread: max_size caps one thread’s LocalPool, not the process. A 48-core server with max_size(16) can therefore hold up to 48 × 16 connections, 16 of them to any one thread’s ring.

Defaults match bb8: max_size 10, min_idle 0, connection_timeout 30s, idle_timeout 10 min, max_lifetime 30 min, test_on_check_out on.

Implementations§

Source§

impl<M: ManageConnection> Builder<M>

Source

pub fn new() -> Self

A builder with the default settings.

Source

pub fn max_size(self, n: u32) -> Self

The most connections one thread’s pool keeps open at once (idle plus checked out). Default 10.

Examples found in repository?
examples/udp_echo.rs (line 72)
61fn main() -> io::Result<()> {
62    let addr: SocketAddr = std::env::args()
63        .nth(1)
64        .unwrap_or_else(|| "0.0.0.0:7000".into())
65        .parse()
66        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
67    let capacity: u32 = std::env::args()
68        .nth(2)
69        .and_then(|s| s.parse().ok())
70        .unwrap_or(1024);
71
72    let pool = Pool::builder().max_size(capacity).build(Buffers);
73
74    let cores = cpu::cores();
75    if cores.is_empty() {
76        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
77    }
78    println!(
79        "udp_echo on {addr}: {} workers, capacity {capacity}/worker",
80        cores.len()
81    );
82
83    let mut handles = Vec::new();
84    for (index, core) in cores.into_iter().enumerate() {
85        let pool = pool.clone();
86        let handle = thread::Builder::new()
87            .name(format!("worker/{index}"))
88            .spawn(move || worker(core, addr, pool))?;
89        handles.push(handle);
90    }
91    for handle in handles {
92        let _ = handle.join();
93    }
94    Ok(())
95}
More examples
Hide additional examples
examples/file_server.rs (line 73)
62fn main() -> io::Result<()> {
63    let addr: SocketAddr = std::env::args()
64        .nth(1)
65        .unwrap_or_else(|| "0.0.0.0:7000".into())
66        .parse()
67        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
68    let capacity: u32 = std::env::args()
69        .nth(2)
70        .and_then(|s| s.parse().ok())
71        .unwrap_or(1024);
72
73    let pool = Pool::builder().max_size(capacity).build(Buffers);
74
75    let cores = cpu::cores();
76    if cores.is_empty() {
77        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
78    }
79    println!(
80        "file_server on {addr} serving {}: {} workers, capacity {capacity}/worker",
81        BASE_DIR.display(),
82        cores.len()
83    );
84
85    let mut handles = Vec::new();
86    for (index, core) in cores.into_iter().enumerate() {
87        let pool = pool.clone();
88        let handle = thread::Builder::new()
89            .name(format!("worker/{index}"))
90            .spawn(move || worker(core, addr, pool))?;
91        handles.push(handle);
92    }
93    for handle in handles {
94        let _ = handle.join();
95    }
96    Ok(())
97}
examples/echo.rs (line 62)
50fn main() -> io::Result<()> {
51    let addr: SocketAddr = std::env::args()
52        .nth(1)
53        .unwrap_or_else(|| "0.0.0.0:7000".into())
54        .parse()
55        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
56    let capacity: u32 = std::env::args()
57        .nth(2)
58        .and_then(|s| s.parse().ok())
59        .unwrap_or(1024);
60
61    // Build the pool once. `Pool` is `Send + Clone`; every worker gets a clone.
62    let pool = Pool::builder().max_size(capacity).build(Buffers);
63
64    let cores = cpu::cores();
65    if cores.is_empty() {
66        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
67    }
68    println!(
69        "echo on {addr}: {} workers, capacity {capacity}/worker",
70        cores.len()
71    );
72
73    let mut handles = Vec::new();
74    for (index, core) in cores.into_iter().enumerate() {
75        let pool = pool.clone();
76        let handle = thread::Builder::new()
77            .name(format!("worker/{index}"))
78            .spawn(move || worker(core, addr, pool))?;
79        handles.push(handle);
80    }
81    for handle in handles {
82        let _ = handle.join();
83    }
84    Ok(())
85}
examples/tcp_pool.rs (line 100)
88fn main() -> io::Result<()> {
89    let addr: SocketAddr = std::env::args()
90        .nth(1)
91        .unwrap_or_else(|| "0.0.0.0:7000".into())
92        .parse()
93        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
94    let capacity: u32 = std::env::args()
95        .nth(2)
96        .and_then(|s| s.parse().ok())
97        .unwrap_or(64);
98
99    // Build the pool once; every worker gets a clone of the `Send` handle.
100    let pool = Pool::builder().max_size(capacity).build(Backend);
101
102    let cores = cpu::cores();
103    if cores.is_empty() {
104        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
105    }
106    println!(
107        "tcp_pool on {addr} -> upstream {}: {} workers, {capacity} upstreams/worker",
108        *UPSTREAM,
109        cores.len()
110    );
111
112    let mut handles = Vec::new();
113    for (index, core) in cores.into_iter().enumerate() {
114        let pool = pool.clone();
115        let handle = thread::Builder::new()
116            .name(format!("worker/{index}"))
117            .spawn(move || worker(core, addr, pool))?;
118        handles.push(handle);
119    }
120    for handle in handles {
121        let _ = handle.join();
122    }
123    Ok(())
124}
examples/wal.rs (line 107)
95fn main() -> io::Result<()> {
96    let addr: SocketAddr = std::env::args()
97        .nth(1)
98        .unwrap_or_else(|| "0.0.0.0:7000".into())
99        .parse()
100        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
101    let capacity: u32 = std::env::args()
102        .nth(2)
103        .and_then(|s| s.parse().ok())
104        .unwrap_or(1024);
105
106    std::fs::create_dir_all(&*WAL_DIR)?;
107    let pool = Pool::builder().max_size(capacity).build(WalManager);
108
109    let cores = cpu::cores();
110    if cores.is_empty() {
111        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
112    }
113    println!(
114        "wal on {addr} -> {} (fdatasync: {}): {} workers, capacity {capacity}/worker",
115        WAL_DIR.display(),
116        if *SYNC { "on" } else { "off" },
117        cores.len()
118    );
119
120    let mut handles = Vec::new();
121    for (index, core) in cores.into_iter().enumerate() {
122        let pool = pool.clone();
123        let handle = thread::Builder::new()
124            .name(format!("worker/{index}"))
125            .spawn(move || worker(core, addr, pool))?;
126        handles.push(handle);
127    }
128    for handle in handles {
129        let _ = handle.join();
130    }
131    Ok(())
132}
examples/task_echo.rs (line 67)
56fn main() -> io::Result<()> {
57    let addr: SocketAddr = std::env::args()
58        .nth(1)
59        .unwrap_or_else(|| "127.0.0.1:7000".into())
60        .parse()
61        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
62    let capacity: u32 = std::env::args()
63        .nth(2)
64        .and_then(|s| s.parse().ok())
65        .unwrap_or(1024);
66
67    let pool = Pool::builder().max_size(capacity).build(Buffers);
68
69    // One runtime, one ring. Everything below runs on this single thread.
70    let runtime = Runtime::builder().build().expect("build compio runtime");
71    runtime.block_on(async move {
72        // This runtime's pool. `!Send`, so it and its buffers stay on this thread.
73        let local = pool.local();
74
75        let listener = TcpListener::bind(addr).await?;
76        println!("task_echo on {addr}: 1 runtime, capacity {capacity}");
77
78        // Accept forever; hand each connection to its own task on this same ring.
79        loop {
80            let Ok((stream, _peer)) = listener.accept().await else {
81                continue;
82            };
83            let _ = stream.set_nodelay(true);
84            compio::runtime::spawn(serve(local.clone(), stream)).detach();
85        }
86    })
87}
Source

pub fn min_idle(self, n: u32) -> Self

How many connections each thread opens up front and keeps idle, created by LocalPool::warm. Capped at max_size. Default 0.

Examples found in repository?
examples/warmup.rs (line 76)
74fn main() -> io::Result<()> {
75    // Keep at most 8 per thread; warm 4 of them ahead of demand.
76    let pool = Pool::builder().max_size(8).min_idle(4).build(Manager);
77
78    // One runtime, one thread — the pool's natural unit.
79    let runtime = Runtime::builder().build().expect("build compio runtime");
80    runtime.block_on(async move {
81        let local = pool.local();
82        println!("fresh pool:     {:?}  opened={}", local.state(), opened());
83
84        // Warm opens min_idle connections up front and parks them on the idle list.
85        let made = local.warm().await.expect("warm");
86        println!(
87            "after warm:     {:?}  opened={}  (warm made {made})",
88            local.state(),
89            opened()
90        );
91
92        // Checking three out pulls them off the warm idle list — no new opens.
93        let a = local.get().await.expect("get a");
94        let b = local.get().await.expect("get b");
95        let c = local.get().await.expect("get c");
96        println!("3 checked out:  {:?}  opened={}", local.state(), opened());
97
98        // Dropping the leases returns the resources to the idle list.
99        drop((a, b, c));
100        println!("3 returned:     {:?}  opened={}", local.state(), opened());
101
102        // A burst reuses the 4 idle resources first, then opens more — but only up
103        // to max_size=8, which caps the pool. A 9th get here would wait for a free
104        // slot rather than open a ninth.
105        let mut held = Vec::new();
106        for _ in 0..8 {
107            held.push(local.get().await.expect("burst"));
108        }
109        println!("8 checked out:  {:?}  opened={}", local.state(), opened());
110
111        drop(held);
112        println!("8 returned:     {:?}  opened={}", local.state(), opened());
113    });
114
115    Ok(())
116}
Source

pub fn connection_timeout(self, d: Duration) -> Self

How long get waits — for a free slot and a live connection — before returning RunError::TimedOut. Default 30s.

Source

pub fn idle_timeout(self, d: Option<Duration>) -> Self

Drop an idle connection that has gone unused for this long. None keeps idle connections forever. Default 10 minutes.

Source

pub fn max_lifetime(self, d: Option<Duration>) -> Self

Drop a connection older than this, idle or not, the next time it is checked out or returned. None never retires on age. Default 30 minutes.

Source

pub fn test_on_check_out(self, yes: bool) -> Self

Call ManageConnection::is_valid on a reused connection as it is checked out. Default true.

Source

pub fn build(self, manager: M) -> Pool<M>

Finish, producing the Send + Clone Pool blueprint.

§Panics

If max_size is 0.

Examples found in repository?
examples/udp_echo.rs (line 72)
61fn main() -> io::Result<()> {
62    let addr: SocketAddr = std::env::args()
63        .nth(1)
64        .unwrap_or_else(|| "0.0.0.0:7000".into())
65        .parse()
66        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
67    let capacity: u32 = std::env::args()
68        .nth(2)
69        .and_then(|s| s.parse().ok())
70        .unwrap_or(1024);
71
72    let pool = Pool::builder().max_size(capacity).build(Buffers);
73
74    let cores = cpu::cores();
75    if cores.is_empty() {
76        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
77    }
78    println!(
79        "udp_echo on {addr}: {} workers, capacity {capacity}/worker",
80        cores.len()
81    );
82
83    let mut handles = Vec::new();
84    for (index, core) in cores.into_iter().enumerate() {
85        let pool = pool.clone();
86        let handle = thread::Builder::new()
87            .name(format!("worker/{index}"))
88            .spawn(move || worker(core, addr, pool))?;
89        handles.push(handle);
90    }
91    for handle in handles {
92        let _ = handle.join();
93    }
94    Ok(())
95}
More examples
Hide additional examples
examples/file_server.rs (line 73)
62fn main() -> io::Result<()> {
63    let addr: SocketAddr = std::env::args()
64        .nth(1)
65        .unwrap_or_else(|| "0.0.0.0:7000".into())
66        .parse()
67        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
68    let capacity: u32 = std::env::args()
69        .nth(2)
70        .and_then(|s| s.parse().ok())
71        .unwrap_or(1024);
72
73    let pool = Pool::builder().max_size(capacity).build(Buffers);
74
75    let cores = cpu::cores();
76    if cores.is_empty() {
77        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
78    }
79    println!(
80        "file_server on {addr} serving {}: {} workers, capacity {capacity}/worker",
81        BASE_DIR.display(),
82        cores.len()
83    );
84
85    let mut handles = Vec::new();
86    for (index, core) in cores.into_iter().enumerate() {
87        let pool = pool.clone();
88        let handle = thread::Builder::new()
89            .name(format!("worker/{index}"))
90            .spawn(move || worker(core, addr, pool))?;
91        handles.push(handle);
92    }
93    for handle in handles {
94        let _ = handle.join();
95    }
96    Ok(())
97}
examples/echo.rs (line 62)
50fn main() -> io::Result<()> {
51    let addr: SocketAddr = std::env::args()
52        .nth(1)
53        .unwrap_or_else(|| "0.0.0.0:7000".into())
54        .parse()
55        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
56    let capacity: u32 = std::env::args()
57        .nth(2)
58        .and_then(|s| s.parse().ok())
59        .unwrap_or(1024);
60
61    // Build the pool once. `Pool` is `Send + Clone`; every worker gets a clone.
62    let pool = Pool::builder().max_size(capacity).build(Buffers);
63
64    let cores = cpu::cores();
65    if cores.is_empty() {
66        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
67    }
68    println!(
69        "echo on {addr}: {} workers, capacity {capacity}/worker",
70        cores.len()
71    );
72
73    let mut handles = Vec::new();
74    for (index, core) in cores.into_iter().enumerate() {
75        let pool = pool.clone();
76        let handle = thread::Builder::new()
77            .name(format!("worker/{index}"))
78            .spawn(move || worker(core, addr, pool))?;
79        handles.push(handle);
80    }
81    for handle in handles {
82        let _ = handle.join();
83    }
84    Ok(())
85}
examples/tcp_pool.rs (line 100)
88fn main() -> io::Result<()> {
89    let addr: SocketAddr = std::env::args()
90        .nth(1)
91        .unwrap_or_else(|| "0.0.0.0:7000".into())
92        .parse()
93        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
94    let capacity: u32 = std::env::args()
95        .nth(2)
96        .and_then(|s| s.parse().ok())
97        .unwrap_or(64);
98
99    // Build the pool once; every worker gets a clone of the `Send` handle.
100    let pool = Pool::builder().max_size(capacity).build(Backend);
101
102    let cores = cpu::cores();
103    if cores.is_empty() {
104        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
105    }
106    println!(
107        "tcp_pool on {addr} -> upstream {}: {} workers, {capacity} upstreams/worker",
108        *UPSTREAM,
109        cores.len()
110    );
111
112    let mut handles = Vec::new();
113    for (index, core) in cores.into_iter().enumerate() {
114        let pool = pool.clone();
115        let handle = thread::Builder::new()
116            .name(format!("worker/{index}"))
117            .spawn(move || worker(core, addr, pool))?;
118        handles.push(handle);
119    }
120    for handle in handles {
121        let _ = handle.join();
122    }
123    Ok(())
124}
examples/wal.rs (line 107)
95fn main() -> io::Result<()> {
96    let addr: SocketAddr = std::env::args()
97        .nth(1)
98        .unwrap_or_else(|| "0.0.0.0:7000".into())
99        .parse()
100        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
101    let capacity: u32 = std::env::args()
102        .nth(2)
103        .and_then(|s| s.parse().ok())
104        .unwrap_or(1024);
105
106    std::fs::create_dir_all(&*WAL_DIR)?;
107    let pool = Pool::builder().max_size(capacity).build(WalManager);
108
109    let cores = cpu::cores();
110    if cores.is_empty() {
111        return Err(io::Error::new(io::ErrorKind::Unsupported, "no cores to run on"));
112    }
113    println!(
114        "wal on {addr} -> {} (fdatasync: {}): {} workers, capacity {capacity}/worker",
115        WAL_DIR.display(),
116        if *SYNC { "on" } else { "off" },
117        cores.len()
118    );
119
120    let mut handles = Vec::new();
121    for (index, core) in cores.into_iter().enumerate() {
122        let pool = pool.clone();
123        let handle = thread::Builder::new()
124            .name(format!("worker/{index}"))
125            .spawn(move || worker(core, addr, pool))?;
126        handles.push(handle);
127    }
128    for handle in handles {
129        let _ = handle.join();
130    }
131    Ok(())
132}
examples/task_echo.rs (line 67)
56fn main() -> io::Result<()> {
57    let addr: SocketAddr = std::env::args()
58        .nth(1)
59        .unwrap_or_else(|| "127.0.0.1:7000".into())
60        .parse()
61        .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, format!("bad address: {e}")))?;
62    let capacity: u32 = std::env::args()
63        .nth(2)
64        .and_then(|s| s.parse().ok())
65        .unwrap_or(1024);
66
67    let pool = Pool::builder().max_size(capacity).build(Buffers);
68
69    // One runtime, one ring. Everything below runs on this single thread.
70    let runtime = Runtime::builder().build().expect("build compio runtime");
71    runtime.block_on(async move {
72        // This runtime's pool. `!Send`, so it and its buffers stay on this thread.
73        let local = pool.local();
74
75        let listener = TcpListener::bind(addr).await?;
76        println!("task_echo on {addr}: 1 runtime, capacity {capacity}");
77
78        // Accept forever; hand each connection to its own task on this same ring.
79        loop {
80            let Ok((stream, _peer)) = listener.accept().await else {
81                continue;
82            };
83            let _ = stream.set_nodelay(true);
84            compio::runtime::spawn(serve(local.clone(), stream)).detach();
85        }
86    })
87}

Trait Implementations§

Source§

impl<M: ManageConnection> Default for Builder<M>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<M> Freeze for Builder<M>
where PhantomData<fn() -> M>: Freeze,

§

impl<M> RefUnwindSafe for Builder<M>
where PhantomData<fn() -> M>: RefUnwindSafe,

§

impl<M> Send for Builder<M>
where PhantomData<fn() -> M>: Send,

§

impl<M> Sync for Builder<M>
where PhantomData<fn() -> M>: Sync,

§

impl<M> Unpin for Builder<M>
where PhantomData<fn() -> M>: Unpin,

§

impl<M> UnsafeUnpin for Builder<M>
where PhantomData<fn() -> M>: UnsafeUnpin,

§

impl<M> UnwindSafe for Builder<M>
where PhantomData<fn() -> M>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more