Skip to main content

BPool

Struct BPool 

Source
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

Source

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 in BPool
  • capacity: capacity of BPool i.e. number of buffers in memory
  • module_id: id used by FrozenErr for 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);
Source

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);
Source

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::allocate after calling BPool::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);

Trait Implementations§

Source§

impl Debug for BPool

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for BPool

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Send for BPool

Source§

impl Sync for BPool

Auto Trait Implementations§

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, 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.