pub struct ExtendableSlab<T, M: FreelistProtection = NoProtection> { /* private fields */ }Expand description
Growable typed slab.
Each segment is a fixed-capacity Slab<T, MmapBacked, M>. Growth allocates
a new MmapBacked and appends a new segment; the previous segments’
pointers remain valid. Segments are never reallocated or moved.
§Thread safety
Send + Sync. The segment list is guarded by a Mutex because we may
need to push to a Vec on growth; per-segment slabs are !Sync but the
mutex serializes access to the list itself. (For high-contention
workloads, switch to SlabOwner/SlabRemote for per-thread
segments.)
§Panic safety
If a thread panics while holding the segments mutex, the mutex is
poisoned. allocate, deallocate, segment_count, and the internal
build_segment helper all call expect("mutex poisoned") and
re-panic on a poisoned lock. This is intentional and asymmetric
with SlabOwner::drop’s into_inner() recovery:
SlabOwner::dropruns during unwind and MUST NOT double-panic, so it recovers the inner state viainto_inner()even on a poisoned mutex.ExtendableSlab::{allocate, deallocate, build_segment, segment_count}run on the normal call path. A poisoned mutex means some prior call panicked under the lock — the allocator state is suspect and the safest policy is fail-loud rather than silently continue. Once poisoned, the wrapper is permanently unusable; the application should treat this as a fatal allocator error and recreate theExtendableSlab.
This asymmetry is intentional and documented here for future maintainers.
Implementations§
Source§impl<T> ExtendableSlab<T, NoProtection>
impl<T> ExtendableSlab<T, NoProtection>
Source§impl<T, M: FreelistProtection> ExtendableSlab<T, M>
impl<T, M: FreelistProtection> ExtendableSlab<T, M>
Sourcepub fn with_protection(segment_capacity: usize, mac_factory: fn() -> M) -> Self
pub fn with_protection(segment_capacity: usize, mac_factory: fn() -> M) -> Self
Construct an empty ExtendableSlab with an explicit freelist-protection factory.
Sourcepub fn with_initial_segments(
count: usize,
segment_capacity: usize,
mac_factory: fn() -> M,
) -> Result<Self, AllocError>
pub fn with_initial_segments( count: usize, segment_capacity: usize, mac_factory: fn() -> M, ) -> Result<Self, AllocError>
Construct with initial_segments segments pre-allocated.
Sourcepub fn segment_count(&self) -> usize
pub fn segment_count(&self) -> usize
Number of segments currently allocated.
Trait Implementations§
Source§impl<T, M: FreelistProtection + Send> Allocator for ExtendableSlab<T, M>where
T: Send,
impl<T, M: FreelistProtection + Send> Allocator for ExtendableSlab<T, M>where
T: Send,
Source§fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>
layout. The returned slice’s length is
at least layout.size() but may be larger.Source§unsafe fn usable_size(
&self,
ptr: NonNull<u8>,
layout: NonZeroLayout,
) -> Option<usize>
unsafe fn usable_size( &self, ptr: NonNull<u8>, layout: NonZeroLayout, ) -> Option<usize>
None — implementors that track usable size
override. Read moreSource§fn capacity_bytes(&self) -> Option<usize>
fn capacity_bytes(&self) -> Option<usize>
None for unbounded
allocators like System. Used by Watermark to compute thresholds.