Skip to main content

BufPool

Struct BufPool 

Source
pub struct BufPool { /* private fields */ }
Expand description

An implementation of a low-latency memory-budgeted buffer pool managing fixed-sized buffer allocations

§Blocking drop

Dropping the BufPool instance from memory blocks unitl all the allocated instances of [BufPoolAllocations] and all there references are dropped from memory.

This is in place to avoid memory leaks, as well as to enable sending BufPoolAllocation objects across threads while being tied to the lifecyle of BufPool.

§Memory Allocations

All the allocations are allocated using the global memory allocator as requested (on-the-fly).

While a single allocation retunred as BufPoolAllocation is a large contineous slice of memory w/ size as BufPoolCfg::buffer_size.bytes() * n_buffers.

Memory layout structure,

allocation = [[buf0][buf1][buf2]]
where,
  - every buffer is of size `buffer_size`
  - each buffer is pointed using `*mut u8`

§Backpressure

Every allocation reserves a memory budget and is only allowed to allocate memory if enough budget (i.e. memory space) is available. Otherwise, the caller is blocked/polled till enough space is available.

When the BufPoolAllocation and all its references are dropped, the underlying memory is deallocated while relaxing the budget and dropping the backpressure (if any).

NOTE: There is no faireness guarantee for the caller’s who are polled when faced with backpressure, as the waiting callers are awaken opportunistically.

§Example

use frozen_core::{
    bufpool::{BufPool, BufPoolCfg, BufferPointer},
    utils::BufferSize,
};

const BUF_SIZE: BufferSize = BufferSize::S16;

let pool = BufPool::new(BufPoolCfg {
    buffer_size: BUF_SIZE,
    max_memory: BUF_SIZE as usize * 0x40,
});

let alloc = pool.allocate(0x30);

assert_eq!(alloc.length(), 0x30);
assert!(!alloc.first().is_null());
assert_eq!(alloc.allocated_bytes(), BUF_SIZE as usize * 0x30);

let ptrs: Vec<BufferPointer> = alloc.iter().collect();
assert_eq!(ptrs.len(), 0x30);

Implementations§

Source§

impl BufPool

Source

pub fn new(cfg: BufPoolCfg) -> Self

Create a new instance of BufPool

§Debug Assertions

In debug builds, this function uses debug_assertion to prevent invalid configurations. Caller must refer to BufPoolCfg for details about the config params.

§Example
use frozen_core::{
    bufpool::{BufPool, BufPoolCfg},
    utils::BufferSize,
};

const BUF_SIZE: BufferSize = BufferSize::S16;

let pool = BufPool::new(BufPoolCfg {
    buffer_size: BUF_SIZE,
    max_memory: BUF_SIZE as usize * 0x0A,
});

let alloc = pool.allocate(1);

assert_eq!(alloc.length(), 1);
assert_eq!(alloc.allocated_bytes(), BUF_SIZE as usize);
Source

pub fn allocate(&self, required: usize) -> BufPoolAllocation

Allocate required number of buffers each of BufPoolCfg::buffer_size size

§Allocation Layout

The allocation is a large contineous slice of memory w/ size as

BufPoolCfg::buffer_size.bytes() * n_buffers

Memory layout structure,

allocation = [[buf0][buf1][buf2]]
where,
  - every buffer is of size `buffer_size`
  - each buffer is pointed using `*mut u8`
§RAII Safety

The allocation object, i.e. BufPoolAllocation, is RAII safe. The allocated memory is automatically deallocated as soon as the last reference to the object is dropped, while also relaxing the memory budget to eliminate backpressure (if any).

§Important Considerations

The number of buffers required should never exceed u16::MAX. This is an abstract soft limit and should be enforced by the public interface to avoid any weird exhaustion issues or unknown bugs across the storage system.

As u16::MAX is large enough value to almost never cause any problems for a single write operation, this soft limit acts as a guidline to safely operate with arithmatic operations across storage engine(s), including but not limited to [frozen_core].

§Example
use frozen_core::{
    bufpool::{BufPool, BufPoolCfg, BufferPointer},
    utils::BufferSize,
};

const BUF_SIZE: BufferSize = BufferSize::S16;

let pool = BufPool::new(BufPoolCfg {
    buffer_size: BUF_SIZE,
    max_memory: BUF_SIZE as usize * 0x14,
});

let alloc = pool.allocate(0x0A);

assert_eq!(alloc.length(), 0x0A);
assert!(!alloc.first().is_null());
assert_eq!(alloc.allocated_bytes(), BUF_SIZE as usize * 0x0A);

let ptrs: Vec<BufferPointer> = alloc.iter().collect();
assert_eq!(ptrs.len(), 0x0A);

Trait Implementations§

Source§

impl Debug for BufPool

Source§

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

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

impl Drop for BufPool

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl Send for BufPool

Source§

impl Sync for BufPool

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.