Skip to main content

SlabOwner

Struct SlabOwner 

Source
pub struct SlabOwner<T, B: Allocator + FixedRange> { /* private fields */ }
Expand description

Owns the slab. Has exclusive allocate access. Send (can be moved across threads) but !Sync (one-at-a-time access — enforced by UnsafeCell on the inner slab plus our manual Send impl with no corresponding Sync impl).

§API-misuse compile-failures (pinned)

SlabOwner is !Sync by construction (_not_sync: PhantomData<Cell<()>>); a future refactor that accidentally rederived Sync would let two threads share an &SlabOwner and race on the UnsafeCell<Slab> inside inner.slab. The compile_fail below pins that rejection:

// FAILS TO COMPILE: SlabOwner is deliberately !Sync. The
// `_not_sync: PhantomData<Cell<()>>` marker blocks the auto-derive,
// and `assert_sync` cannot accept a `!Sync` type.
use forge_alloc::InlineBacked;
use forge_alloc::SlabOwner;
fn assert_sync<T: Sync>() {}
assert_sync::<SlabOwner<u64, InlineBacked<512>>>();

Implementations§

Source§

impl<T, B: Allocator + FixedRange> SlabOwner<T, B>

Source

pub fn new(capacity: usize, backing: B) -> Result<Self, AllocError>

Construct, taking ownership of a freshly-built slab.

Source

pub fn with_batch_policy( capacity: usize, backing: B, batch_policy: BatchPolicy, queue_capacity: usize, ) -> Result<Self, AllocError>

Construct with explicit batch policy and queue capacity.

Source

pub fn remote(&self) -> SlabRemote<T, B>

Create a remote handle. Cheap — just an Arc clone.

Source

pub fn drain(&self)

Drain the remote-free queue into the local freelist now.

Holds the queue mutex only long enough to swap out the pending entries; releases the lock before calling slab.deallocate for each entry. Without this two-phase pattern, remote senders would be blocked through the entire drain loop — death by lock-hold time proportional to queue depth.

Source

pub fn adaptive_threshold_snapshot(&self) -> Option<usize>

Current adaptive-step threshold (in remote-queue entries), or None if the owner is configured with BatchPolicy::Fixed. Useful in tests and adaptive-tuning telemetry.

Trait Implementations§

Source§

impl<T, B: Allocator + FixedRange> Allocator for SlabOwner<T, B>

Source§

fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>

Allocate a block satisfying 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>

Usable size of an existing allocation, if the allocator can report it. Defaults to None — implementors that track usable size override. Read more
Source§

fn capacity_bytes(&self) -> Option<usize>

Total bytes this allocator can issue, if bounded. None for unbounded allocators like System. Used by Watermark to compute thresholds.
Source§

fn corruption_events(&self) -> u64

Detected freelist / metadata corruption events observed by this allocator since construction. Read more
Source§

fn allocate_zeroed( &self, layout: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Allocate a zero-initialized block.
Source§

unsafe fn grow( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Grow an allocation in place if possible, otherwise allocate-copy-free. Read more
Source§

unsafe fn shrink( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Shrink an allocation in place if possible, otherwise allocate-copy-free. Read more
Source§

fn reset(&mut self) -> Result<(), AllocError>

Reclaim everything previously allocated. Default impl returns AllocError — only arena-style allocators implement a meaningful reset. Read more
Source§

impl<T, B: Allocator + FixedRange> Deallocator for SlabOwner<T, B>

Source§

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: NonZeroLayout)

Release a previously allocated block. Read more
Source§

impl<T, B: Allocator + FixedRange> Drop for SlabOwner<T, B>

Final drain on owner drop. Without this:

  • SlabRemote clones outliving the owner would push entries into remote_queue that nothing ever drains.
  • Slots queued for return (already routed by the remote, not yet drained by the owner) would never be reclaimed back into the slab’s local freelist. The slab keeps those slots marked-live for as long as the last remote keeps the Arc<SlabInner> alive — operationally a slot-table leak. Note that T’s destructor is the remote caller’s responsibility BEFORE calling SlabRemote::deallocate (per the Slab::deallocate safety contract); the drain here only reclaims the freelist entry, it does not run T::drop.
  • Subsequent SlabRemote::deallocate (the spinning, infallible variant) would spin forever on a full queue, hanging the calling thread.

We close the queue while holding its mutex (race-free against any in-flight remote push) and drain the pending entries into the local freelist. After this, the slab is consistent and any further remote push observes closed == true and returns Err(ptr) / no-ops without spinning.

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<T, B: Allocator + FixedRange> FixedRange for SlabOwner<T, B>

Source§

fn base(&self) -> NonNull<u8>

First byte of the owned address range. Read more
Source§

fn size(&self) -> usize

Length in bytes of the owned address range. Read more
Source§

fn commit(&self, offset: usize, len: usize) -> Result<(), AllocError>

Ensure the bytes [offset, offset + len) (relative to base) are backed by committed, writable memory before a consumer writes through them. Read more
Source§

fn contains(&self, ptr: NonNull<u8>) -> bool

Whether ptr lies within [base, base + size). Read more
Source§

impl<T: Send, B: Allocator + FixedRange + Send> Send for SlabOwner<T, B>

Auto Trait Implementations§

§

impl<T, B> !Freeze for SlabOwner<T, B>

§

impl<T, B> !RefUnwindSafe for SlabOwner<T, B>

§

impl<T, B> !Sync for SlabOwner<T, B>

§

impl<T, B> !UnwindSafe for SlabOwner<T, B>

§

impl<T, B> Unpin for SlabOwner<T, B>

§

impl<T, B> UnsafeUnpin for SlabOwner<T, B>

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.