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>
impl<M: ManageConnection> Builder<M>
Sourcepub fn max_size(self, n: u32) -> Self
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?
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
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}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}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}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}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}Sourcepub fn min_idle(self, n: u32) -> Self
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?
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}Sourcepub fn connection_timeout(self, d: Duration) -> Self
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.
Sourcepub fn idle_timeout(self, d: Option<Duration>) -> Self
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.
Sourcepub fn max_lifetime(self, d: Option<Duration>) -> Self
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.
Sourcepub fn test_on_check_out(self, yes: bool) -> Self
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.
Sourcepub fn build(self, manager: M) -> Pool<M>
pub fn build(self, manager: M) -> Pool<M>
Examples found in repository?
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
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}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}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}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}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§
Auto Trait Implementations§
impl<M> Freeze for Builder<M>
impl<M> RefUnwindSafe for Builder<M>
impl<M> Send for Builder<M>
impl<M> Sync for Builder<M>
impl<M> Unpin for Builder<M>
impl<M> UnsafeUnpin for Builder<M>
impl<M> UnwindSafe for Builder<M>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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