pub struct BPool { /* private fields */ }Expand description
Lock-free buffer pool used for staging IO buffers
§Features
- RAII Safe
- Graceful Shutdown
- Lock-free fast path
§Pooling for allocations
Bufs are allocated in batches using BPool::allocate, it may allocate fewer than requested, in such cases
caller should wait using BPool::wait which block till any bufs are available to use again
§Example
const MODULE_ID: u8 = 0;
const CAPACITY: usize = 4;
const BUF_SIZE: usize = 0x20;
let pool = frozen_core::bpool::BPool::new(BUF_SIZE, CAPACITY, MODULE_ID);
{
// NOTE: allocations are RAII safe, hence the underlying resource is reused when `alloc` is dropped
let alloc = pool.allocate(4);
assert_eq!(alloc.count, 4);
}
let alloc2 = pool.allocate(4);
assert_eq!(alloc2.count, 4);Implementations§
Source§impl BPool
impl BPool
Sourcepub fn new(buf_size: usize, capacity: usize, module_id: u8) -> Self
pub fn new(buf_size: usize, capacity: usize, module_id: u8) -> Self
Create a new instance of BPool
§Params
buf_size: size of each buf inBPoolcapacity: capacity ofBPooli.e. number of buffers in memorymodule_id: id used byFrozenErrfor error propagation
§Example
const MODULE_ID: u8 = 0;
const CAPACITY: usize = 4;
const BUF_SIZE: usize = 0x20;
let pool = frozen_core::bpool::BPool::new(BUF_SIZE, CAPACITY, MODULE_ID);
{
// NOTE: allocations are RAII safe, hence the underlying resource is reused when `alloc` is dropped
let alloc = pool.allocate(4);
assert_eq!(alloc.count, 4);
}
let alloc2 = pool.allocate(4);
assert_eq!(alloc2.count, 4);Sourcepub fn allocate<'a>(&'a self, n: usize) -> Allocation<'a>
pub fn allocate<'a>(&'a self, n: usize) -> Allocation<'a>
Allocates N buffers for staging IO ops
§Calling Pattern
remaining = n
loop
alloc = allocate(remaining)
if alloc.count == 0
wait()
continue
remaining -= alloc.count
if remaining == 0
break§Polling
This function may not allocate all the N required buffers in one call, so the caller must
poll (wait and retry) for remaining N buffers
§RAII Safety
All BPool aloocations are RAII safe by default, hence when the variable which stores the result
of allocate, is dropped, the buffer’s it holds are also automatically freed, the burden of freeing after use
does not fall on the caller
§Example
const MODULE_ID: u8 = 0;
const CAPACITY: usize = 4;
const BUF_SIZE: usize = 0x20;
let pool = frozen_core::bpool::BPool::new(BUF_SIZE, CAPACITY, MODULE_ID);
let alloc1 = pool.allocate(4);
assert!(alloc1.count == 4);
let alloc2 = pool.allocate(1);
assert!(alloc2.count == 0);
drop(alloc1);
let alloc3 = pool.allocate(1);
assert!(alloc3.count == 1);Sourcepub fn wait(&self) -> FrozenRes<()>
pub fn wait(&self) -> FrozenRes<()>
Block until at least one buffer becomes available
This function is intended to be used when BPool::allocate returns less than requested bufs,
i.e. when pool is exhausted
§Polling
The typical allocation pattern is,
- Attempt allocation w/
BPool::allocate - If less than requested bufs are allocated, call
BPool::wait - Retry the allocation; all within a loop
§Notes
- The caller must retry
BPool::allocateafter callingBPool::wait - Only threads waiting for buffers are blocked, the allocation fast path remains lock-free
§Example
const MODULE_ID: u8 = 0;
const CAPACITY: usize = 2;
const BUF_SIZE: usize = 0x20;
let pool = frozen_core::bpool::BPool::new(BUF_SIZE, CAPACITY, MODULE_ID);
let alloc = pool.allocate(2);
assert_eq!(alloc.count, 2);
let empty = pool.allocate(1);
assert_eq!(empty.count, 0);
drop(alloc);
pool.wait().expect("wait failed");
let alloc2 = pool.allocate(1);
assert_eq!(alloc2.count, 1);