From bf95e9b56a0a3410046a5cdd5f6b5e3f40e901ad Mon Sep 17 00:00:00 2001 From: RJ Rybarczyk Date: Tue, 22 Oct 2024 07:23:33 -0400 Subject: [PATCH] Back buffer pool docs --- utils/buffer/src/buffer_pool/pool_back.rs | 64 ++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/utils/buffer/src/buffer_pool/pool_back.rs b/utils/buffer/src/buffer_pool/pool_back.rs index ad89bf1696..453d799211 100644 --- a/utils/buffer/src/buffer_pool/pool_back.rs +++ b/utils/buffer/src/buffer_pool/pool_back.rs @@ -1,12 +1,42 @@ +// # 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, @@ -14,11 +44,13 @@ impl PoolBack { } } + /// 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; @@ -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, @@ -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, @@ -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, @@ -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,