Skip to content

Commit

Permalink
Back buffer pool docs
Browse files Browse the repository at this point in the history
  • Loading branch information
rrybarczyk committed Oct 22, 2024
1 parent 3ccb85f commit bf95e9b
Showing 1 changed file with 63 additions and 1 deletion.
64 changes: 63 additions & 1 deletion utils/buffer/src/buffer_pool/pool_back.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,56 @@
// # Back of Buffer Pool
//!
//! Manages the "back" section of the buffer pool ([`crate::BufferPool`]).
//!
//! The [`PoolBack`] struct is responsible for allocating, clearing, and managing memory slices
//! in the back part of the pool, allowing efficient memory reuse in high-throughput environments.
//! It tracks the number of allocated slices and attempts to free up memory that is no longer in
//! use, preventing unnecessary memory growth.
//!
//! Key functions in this module handle:
//! - Clearing unused slices from the back of the pool to reclaim memory.
//! - Managing slice allocation and ensuring enough capacity for new operations.
//! - Switching between different pool modes, such as front or back, depending on memory state.
//!
//! Memory in the back of the pool buffer is always favored to be used first. If the back of the
//! pool fills up, the buffer pool switches to use the front of the pool instead. The front of the
//! pool will be used until the back of the pool has been cleared, or until both the back and front
//! are filled, in which case the buffer pool switches to allocate system memory at reduced
//! performance.
use crate::buffer_pool::{InnerMemory, PoolFront, PoolMode, POOL_CAPACITY};

/// Manages the "back" section of the [`crate::BufferPool`].
///
/// Handles the allocation of memory slices at the back of the buffer pool. It tracks the number
/// of slices in use and attempts to free unused slices when necessary to maximize available
/// memory. The back of the buffer pool is used first, if it fills up, the front of the buffer pool
/// is used.
#[derive(Debug, Clone)]
pub struct PoolBack {
// Starting index of the back section in the buffer pool.
back_start: usize,

// Number of allocated slices in the back section.
len: usize,
}

impl PoolBack {
/// Initializes a new `PoolBack` with no allocated slices.
pub fn new() -> Self {
Self {
back_start: 0,
len: 0,
}
}

/// Returns the number of allocated slices in the back section of the buffer pool.
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}

/// Updates the length of the back section based on the state of the inner memory.
#[inline(always)]
pub fn set_len_from_inner_memory(&mut self, len: usize) {
let len = len - self.back_start;
Expand All @@ -29,17 +61,27 @@ impl PoolBack {
self.len = len;
}

/// Returns the starting index of the back section in the buffer pool.
#[inline(always)]
pub fn back_start(&self) -> usize {
self.back_start
}

/// Resets the back section of the pool by clearing its start index and length.
#[inline(always)]
pub fn reset(&mut self) {
self.back_start = 0;
self.len = 0;
}

/// Attempts to clear unused slices at the tail of the back section without performing bounds
/// or safety checks.
///
/// Assumes the caller has already ensured the safety of the operation (such as slice bounds
/// and memory validity). It skips internal safety checks, relying on the caller to manage the
/// state, making it faster but potentially unsafe if misused.
///
/// Returns `true` if the tail was cleared successfully, otherwise `false`.
#[inline(always)]
pub fn try_clear_tail_unchecked(
&mut self,
Expand Down Expand Up @@ -91,14 +133,24 @@ impl PoolBack {
}
}

/// Checks if the tail of the back section can be cleared.
///
/// Should always be called before attempting to clear the tail. Returns `true` if the tail can
/// be cleared, otherwise `false`.
#[inline(always)]
// Check if it is possible to clear the tail it must always be called before try_clear_tail
pub fn tail_is_clearable(&self, shared_state: u8) -> bool {
let element_in_back = POOL_CAPACITY - self.back_start;
let element_to_drop = usize::min(element_in_back, shared_state.trailing_zeros() as usize);

element_to_drop <= self.len && self.back_start + self.len >= POOL_CAPACITY
}

// Attempts to clear the head of the back section, transitioning to the buffer pool front
// section if not possible.
//
// Returns `Ok` if the head was cleared successfully. Otherwise an `Err(PoolMode::Front)` if
// the buffer pool should switch to front mode, or an `Err(PoolMode::Alloc)` if the buffer pool
// should switch to allocation mode.
#[inline(always)]
fn try_clear_head(
&mut self,
Expand Down Expand Up @@ -126,6 +178,11 @@ impl PoolBack {
}
}

/// Clears the tail or head of the back section, transitioning pool modes if necessary.
///
// Returns `Ok` if the tail or head was cleared successfully. Otherwise an
// `Err(PoolMode::Front)` if the buffer pool should switch to front mode, or an
// `Err(PoolMode::Alloc)` if the buffer pool should switch to allocation mode.
#[inline(always)]
pub fn clear_unchecked(
&mut self,
Expand All @@ -142,6 +199,11 @@ impl PoolBack {
self.try_clear_head(shared_state, memory)
}

/// Returns a writable slice of memory from the back section or transitions to a new pool mode
/// if necessary.
///
/// Returns `Ok(*mut u8)` if writable memory is available, otherwise an `Err(PoolMode)` if a
/// mode change is required.
#[inline(always)]
pub fn get_writable(
&mut self,
Expand Down

0 comments on commit bf95e9b

Please sign in to comment.