blob: 115e36eefae3f2580bcc3dfc2d716144da2a8f8e [file] [log] [blame]
//! A lock-free concurrent object pool.
//!
//! See the [`Pool` type's documentation][pool] for details on the object pool API and how
//! it differs from the [`Slab`] API.
//!
//! [pool]: ../struct.Pool.html
//! [`Slab`]: ../struct.Slab.html
use crate::{
cfg::{self, CfgPrivate, DefaultConfig},
clear::Clear,
page, shard,
tid::Tid,
Pack, Shard,
};
use std::{fmt, marker::PhantomData, sync::Arc};
/// A lock-free concurrent object pool.
///
/// Slabs provide pre-allocated storage for many instances of a single type. But, when working with
/// heap allocated objects, the advantages of a slab are lost, as the memory allocated for the
/// object is freed when the object is removed from the slab. With a pool, we can instead reuse
/// this memory for objects being added to the pool in the future, therefore reducing memory
/// fragmentation and avoiding additional allocations.
///
/// This type implements a lock-free concurrent pool, indexed by `usize`s. The items stored in this
/// type need to implement [`Clear`] and `Default`.
///
/// The `Pool` type shares similar semantics to [`Slab`] when it comes to sharing across threads
/// and storing mutable shared data. The biggest difference is there are no [`Slab::insert`] and
/// [`Slab::take`] analouges for the `Pool` type. Instead new items are added to the pool by using
/// the [`Pool::create`] method, and marked for clearing by the [`Pool::clear`] method.
///
/// # Examples
///
/// Add an entry to the pool, returning an index:
/// ```
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
///
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// ```
///
/// Create a new pooled item, returning a guard that allows mutable access:
/// ```
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
///
/// let mut guard = pool.create().unwrap();
/// let key = guard.key();
/// guard.push_str("hello world");
///
/// drop(guard); // release the guard, allowing immutable access.
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// ```
///
/// Pool entries can be cleared by calling [`Pool::clear`]. This marks the entry to
/// be cleared when the guards referencing to it are dropped.
/// ```
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
///
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Mark this entry to be cleared.
/// pool.clear(key);
///
/// // The cleared entry is no longer available in the pool
/// assert!(pool.get(key).is_none());
/// ```
/// # Configuration
///
/// Both `Pool` and [`Slab`] share the same configuration mechanism. See [crate level documentation][config-doc]
/// for more details.
///
/// [`Slab::take`]: crate::Slab::take
/// [`Slab::insert`]: crate::Slab::insert
/// [`Pool::create`]: Pool::create
/// [`Pool::clear`]: Pool::clear
/// [config-doc]: crate#configuration
/// [`Clear`]: crate::Clear
/// [`Slab`]: crate::Slab
pub struct Pool<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
shards: shard::Array<T, C>,
_cfg: PhantomData<C>,
}
/// A guard that allows access to an object in a pool.
///
/// While the guard exists, it indicates to the pool that the item the guard references is
/// currently being accessed. If the item is removed from the pool while the guard exists, the
/// removal will be deferred until all guards are dropped.
pub struct Ref<'a, T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::Guard<T, C>,
shard: &'a Shard<T, C>,
key: usize,
}
/// A guard that allows exclusive mutable access to an object in a pool.
///
/// While the guard exists, it indicates to the pool that the item the guard
/// references is currently being accessed. If the item is removed from the pool
/// while a guard exists, the removal will be deferred until the guard is
/// dropped. The slot cannot be accessed by other threads while it is accessed
/// mutably.
pub struct RefMut<'a, T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::InitGuard<T, C>,
shard: &'a Shard<T, C>,
key: usize,
}
/// An owned guard that allows shared immutable access to an object in a pool.
///
/// While the guard exists, it indicates to the pool that the item the guard references is
/// currently being accessed. If the item is removed from the pool while the guard exists, the
/// removal will be deferred until all guards are dropped.
///
/// Unlike [`Ref`], which borrows the pool, an `OwnedRef` clones the `Arc`
/// around the pool. Therefore, it keeps the pool from being dropped until all
/// such guards have been dropped. This means that an `OwnedRef` may be held for
/// an arbitrary lifetime.
///
///
/// # Examples
///
/// ```
/// # use sharded_slab::Pool;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let value = pool.clone().get_owned(key).unwrap();
///
/// // Now, the original `Arc` clone of the pool may be dropped, but the
/// // returned `OwnedRef` can still access the value.
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// Unlike [`Ref`], an `OwnedRef` may be stored in a struct which must live
/// for the `'static` lifetime:
///
/// ```
/// # use sharded_slab::Pool;
/// use sharded_slab::pool::OwnedRef;
/// use std::sync::Arc;
///
/// pub struct MyStruct {
/// pool_ref: OwnedRef<String>,
/// // ... other fields ...
/// }
///
/// // Suppose this is some arbitrary function which requires a value that
/// // lives for the 'static lifetime...
/// fn function_requiring_static<T: 'static>(t: &T) {
/// // ... do something extremely important and interesting ...
/// }
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let pool_ref = pool.clone().get_owned(key).unwrap();
/// let my_struct = MyStruct {
/// pool_ref,
/// // ...
/// };
///
/// // We can use `my_struct` anywhere where it is required to have the
/// // `'static` lifetime:
/// function_requiring_static(&my_struct);
/// ```
///
/// `OwnedRef`s may be sent between threads:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let value = pool.clone().get_owned(key).unwrap();
///
/// thread::spawn(move || {
/// assert_eq!(value, String::from("hello world"));
/// // ...
/// }).join().unwrap();
/// ```
///
/// [`Ref`]: crate::pool::Ref
pub struct OwnedRef<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::Guard<T, C>,
pool: Arc<Pool<T, C>>,
key: usize,
}
/// An owned guard that allows exclusive, mutable access to an object in a pool.
///
/// An `OwnedRefMut<T>` functions more or less identically to an owned
/// `Box<T>`: it can be passed to functions, stored in structure fields, and
/// borrowed mutably or immutably, and can be owned for arbitrary lifetimes.
/// The difference is that, unlike a `Box<T>`, the memory allocation for the
/// `T` lives in the `Pool`; when an `OwnedRefMut` is created, it may reuse
/// memory that was allocated for a previous pooled object that has been
/// cleared. Additionally, the `OwnedRefMut` may be [downgraded] to an
/// [`OwnedRef`] which may be shared freely, essentially turning the `Box`
/// into an `Arc`.
///
/// This is returned by [`Pool::create_owned`].
///
/// While the guard exists, it indicates to the pool that the item the guard
/// references is currently being accessed. If the item is removed from the pool
/// while the guard exists, theremoval will be deferred until all guards are
/// dropped.
///
/// Unlike [`RefMut`], which borrows the pool, an `OwnedRefMut` clones the `Arc`
/// around the pool. Therefore, it keeps the pool from being dropped until all
/// such guards have been dropped. This means that an `OwnedRefMut` may be held for
/// an arbitrary lifetime.
///
/// # Examples
///
/// ```rust
/// # use sharded_slab::Pool;
/// # use std::thread;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new pooled item, returning an owned guard that allows mutable
/// // access to the new item.
/// let mut item = pool.clone().create_owned().unwrap();
/// // Return a key that allows indexing the created item once the guard
/// // has been dropped.
/// let key = item.key();
///
/// // Mutate the item.
/// item.push_str("Hello");
/// // Drop the guard, releasing mutable access to the new item.
/// drop(item);
///
/// /// Other threads may now (immutably) access the item using the returned key.
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("Hello"));
/// }).join().unwrap();
/// ```
///
/// ```rust
/// # use sharded_slab::Pool;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new item, returning an owned, mutable guard.
/// let mut value = pool.clone().create_owned().unwrap();
///
/// // Now, the original `Arc` clone of the pool may be dropped, but the
/// // returned `OwnedRefMut` can still access the value.
/// drop(pool);
///
/// value.push_str("hello world");
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// Unlike [`RefMut`], an `OwnedRefMut` may be stored in a struct which must live
/// for the `'static` lifetime:
///
/// ```
/// # use sharded_slab::Pool;
/// use sharded_slab::pool::OwnedRefMut;
/// use std::sync::Arc;
///
/// pub struct MyStruct {
/// pool_ref: OwnedRefMut<String>,
/// // ... other fields ...
/// }
///
/// // Suppose this is some arbitrary function which requires a value that
/// // lives for the 'static lifetime...
/// fn function_requiring_static<T: 'static>(t: &T) {
/// // ... do something extremely important and interesting ...
/// }
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new item, returning a mutable owned reference.
/// let pool_ref = pool.clone().create_owned().unwrap();
///
/// let my_struct = MyStruct {
/// pool_ref,
/// // ...
/// };
///
/// // We can use `my_struct` anywhere where it is required to have the
/// // `'static` lifetime:
/// function_requiring_static(&my_struct);
/// ```
///
/// `OwnedRefMut`s may be sent between threads:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// let mut value = pool.clone().create_owned().unwrap();
/// let key = value.key();
///
/// thread::spawn(move || {
/// value.push_str("hello world");
/// // ...
/// }).join().unwrap();
///
/// // Once the `OwnedRefMut` has been dropped by the other thread, we may
/// // now access the value immutably on this thread.
///
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// ```
///
/// Downgrading from a mutable to an immutable reference:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// let mut value = pool.clone().create_owned().unwrap();
/// let key = value.key();
/// value.push_str("hello world");
///
/// // Downgrade the mutable owned ref to an immutable owned ref.
/// let value = value.downgrade();
///
/// // Once the `OwnedRefMut` has been downgraded, other threads may
/// // immutably access the pooled value:
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// }).join().unwrap();
///
/// // This thread can still access the pooled value through the
/// // immutable owned ref:
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// [`Pool::create_owned`]: crate::Pool::create_owned
/// [`RefMut`]: crate::pool::RefMut
/// [`OwnedRefMut`]: crate::pool::OwnedRefMut
/// [downgraded]: crate::pool::OwnedRefMut::downgrade
pub struct OwnedRefMut<T, C = DefaultConfig>
where
T: Clear + Default,
C: cfg::Config,
{
inner: page::slot::InitGuard<T, C>,
pool: Arc<Pool<T, C>>,
key: usize,
}
impl<T> Pool<T>
where
T: Clear + Default,
{
/// Returns a new `Pool` with the default configuration parameters.
pub fn new() -> Self {
Self::new_with_config()
}
/// Returns a new `Pool` with the provided configuration parameters.
pub fn new_with_config<C: cfg::Config>() -> Pool<T, C> {
C::validate();
Pool {
shards: shard::Array::new(),
_cfg: PhantomData,
}
}
}
impl<T, C> Pool<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
/// The number of bits in each index which are used by the pool.
///
/// If other data is packed into the `usize` indices returned by
/// [`Pool::create`], user code is free to use any bits higher than the
/// `USED_BITS`-th bit freely.
///
/// This is determined by the [`Config`] type that configures the pool's
/// parameters. By default, all bits are used; this can be changed by
/// overriding the [`Config::RESERVED_BITS`][res] constant.
///
/// [`Config`]: trait.Config.html
/// [res]: trait.Config.html#associatedconstant.RESERVED_BITS
/// [`Slab::insert`]: struct.Slab.html#method.insert
pub const USED_BITS: usize = C::USED_BITS;
/// Creates a new object in the pool, returning an [`RefMut`] guard that
/// may be used to mutate the new object.
///
/// If this function returns `None`, then the shard for the current thread is full and no items
/// can be added until some are removed, or the maximum number of shards has been reached.
///
/// # Examples
/// ```rust
/// # use sharded_slab::Pool;
/// # use std::thread;
/// let pool: Pool<String> = Pool::new();
///
/// // Create a new pooled item, returning a guard that allows mutable
/// // access to the new item.
/// let mut item = pool.create().unwrap();
/// // Return a key that allows indexing the created item once the guard
/// // has been dropped.
/// let key = item.key();
///
/// // Mutate the item.
/// item.push_str("Hello");
/// // Drop the guard, releasing mutable access to the new item.
/// drop(item);
///
/// /// Other threads may now (immutably) access the item using the returned key.
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("Hello"));
/// }).join().unwrap();
/// ```
///
/// [`RefMut`]: crate::pool::RefMut
pub fn create(&self) -> Option<RefMut<'_, T, C>> {
let (tid, shard) = self.shards.current();
test_println!("pool: create {:?}", tid);
let (key, inner) = shard.init_with(|idx, slot| {
let guard = slot.init()?;
let gen = guard.generation();
Some((gen.pack(idx), guard))
})?;
Some(RefMut {
inner,
key: tid.pack(key),
shard,
})
}
/// Creates a new object in the pool, returning an [`OwnedRefMut`] guard that
/// may be used to mutate the new object.
///
/// If this function returns `None`, then the shard for the current thread
/// is full and no items can be added until some are removed, or the maximum
/// number of shards has been reached.
///
/// Unlike [`create`], which borrows the pool, this method _clones_ the `Arc`
/// around the pool if a value exists for the given key. This means that the
/// returned [`OwnedRefMut`] can be held for an arbitrary lifetime. However,
/// this method requires that the pool itself be wrapped in an `Arc`.
///
/// An `OwnedRefMut<T>` functions more or less identically to an owned
/// `Box<T>`: it can be passed to functions, stored in structure fields, and
/// borrowed mutably or immutably, and can be owned for arbitrary lifetimes.
/// The difference is that, unlike a `Box<T>`, the memory allocation for the
/// `T` lives in the `Pool`; when an `OwnedRefMut` is created, it may reuse
/// memory that was allocated for a previous pooled object that has been
/// cleared. Additionally, the `OwnedRefMut` may be [downgraded] to an
/// [`OwnedRef`] which may be shared freely, essentially turning the `Box`
/// into an `Arc`.
///
/// # Examples
///
/// ```rust
/// # use sharded_slab::Pool;
/// # use std::thread;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new pooled item, returning an owned guard that allows mutable
/// // access to the new item.
/// let mut item = pool.clone().create_owned().unwrap();
/// // Return a key that allows indexing the created item once the guard
/// // has been dropped.
/// let key = item.key();
///
/// // Mutate the item.
/// item.push_str("Hello");
/// // Drop the guard, releasing mutable access to the new item.
/// drop(item);
///
/// /// Other threads may now (immutably) access the item using the returned key.
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("Hello"));
/// }).join().unwrap();
/// ```
///
/// ```rust
/// # use sharded_slab::Pool;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new item, returning an owned, mutable guard.
/// let mut value = pool.clone().create_owned().unwrap();
///
/// // Now, the original `Arc` clone of the pool may be dropped, but the
/// // returned `OwnedRefMut` can still access the value.
/// drop(pool);
///
/// value.push_str("hello world");
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// Unlike [`RefMut`], an `OwnedRefMut` may be stored in a struct which must live
/// for the `'static` lifetime:
///
/// ```
/// # use sharded_slab::Pool;
/// use sharded_slab::pool::OwnedRefMut;
/// use std::sync::Arc;
///
/// pub struct MyStruct {
/// pool_ref: OwnedRefMut<String>,
/// // ... other fields ...
/// }
///
/// // Suppose this is some arbitrary function which requires a value that
/// // lives for the 'static lifetime...
/// fn function_requiring_static<T: 'static>(t: &T) {
/// // ... do something extremely important and interesting ...
/// }
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// // Create a new item, returning a mutable owned reference.
/// let pool_ref = pool.clone().create_owned().unwrap();
///
/// let my_struct = MyStruct {
/// pool_ref,
/// // ...
/// };
///
/// // We can use `my_struct` anywhere where it is required to have the
/// // `'static` lifetime:
/// function_requiring_static(&my_struct);
/// ```
///
/// `OwnedRefMut`s may be sent between threads:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// let mut value = pool.clone().create_owned().unwrap();
/// let key = value.key();
///
/// thread::spawn(move || {
/// value.push_str("hello world");
/// // ...
/// }).join().unwrap();
///
/// // Once the `OwnedRefMut` has been dropped by the other thread, we may
/// // now access the value immutably on this thread.
///
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// ```
///
/// Downgrading from a mutable to an immutable reference:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
///
/// let mut value = pool.clone().create_owned().unwrap();
/// let key = value.key();
/// value.push_str("hello world");
///
/// // Downgrade the mutable owned ref to an immutable owned ref.
/// let value = value.downgrade();
///
/// // Once the `OwnedRefMut` has been downgraded, other threads may
/// // immutably access the pooled value:
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// }).join().unwrap();
///
/// // This thread can still access the pooled value through the
/// // immutable owned ref:
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// [`create`]: Pool::create
/// [`OwnedRef`]: crate::pool::OwnedRef
/// [`RefMut`]: crate::pool::RefMut
/// [`OwnedRefMut`]: crate::pool::OwnedRefMut
/// [downgraded]: crate::pool::OwnedRefMut::downgrade
pub fn create_owned(self: Arc<Self>) -> Option<OwnedRefMut<T, C>> {
let (tid, shard) = self.shards.current();
test_println!("pool: create_owned {:?}", tid);
let (inner, key) = shard.init_with(|idx, slot| {
let inner = slot.init()?;
let gen = inner.generation();
Some((inner, tid.pack(gen.pack(idx))))
})?;
Some(OwnedRefMut {
inner,
pool: self,
key,
})
}
/// Creates a new object in the pool with the provided initializer,
/// returning a key that may be used to access the new object.
///
/// If this function returns `None`, then the shard for the current thread is full and no items
/// can be added until some are removed, or the maximum number of shards has been reached.
///
/// # Examples
/// ```rust
/// # use sharded_slab::Pool;
/// # use std::thread;
/// let pool: Pool<String> = Pool::new();
///
/// // Create a new pooled item, returning its integer key.
/// let key = pool.create_with(|s| s.push_str("Hello")).unwrap();
///
/// /// Other threads may now (immutably) access the item using the key.
/// thread::spawn(move || {
/// assert_eq!(pool.get(key).unwrap(), String::from("Hello"));
/// }).join().unwrap();
/// ```
pub fn create_with(&self, init: impl FnOnce(&mut T)) -> Option<usize> {
test_println!("pool: create_with");
let mut guard = self.create()?;
init(&mut guard);
Some(guard.key())
}
/// Return a borrowed reference to the value associated with the given key.
///
/// If the pool does not contain a value for the given key, `None` is returned instead.
///
/// # Examples
///
/// ```rust
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
/// assert!(pool.get(12345).is_none());
/// ```
pub fn get(&self, key: usize) -> Option<Ref<'_, T, C>> {
let tid = C::unpack_tid(key);
test_println!("pool: get{:?}; current={:?}", tid, Tid::<C>::current());
let shard = self.shards.get(tid.as_usize())?;
let inner = shard.with_slot(key, |slot| slot.get(C::unpack_gen(key)))?;
Some(Ref { inner, shard, key })
}
/// Return an owned reference to the value associated with the given key.
///
/// If the pool does not contain a value for the given key, `None` is
/// returned instead.
///
/// Unlike [`get`], which borrows the pool, this method _clones_ the `Arc`
/// around the pool if a value exists for the given key. This means that the
/// returned [`OwnedRef`] can be held for an arbitrary lifetime. However,
/// this method requires that the pool itself be wrapped in an `Arc`.
///
/// # Examples
///
/// ```rust
/// # use sharded_slab::Pool;
/// use std::sync::Arc;
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let value = pool.clone().get_owned(key).unwrap();
///
/// // Now, the original `Arc` clone of the pool may be dropped, but the
/// // returned `OwnedRef` can still access the value.
/// assert_eq!(value, String::from("hello world"));
/// ```
///
/// Unlike [`Ref`], an `OwnedRef` may be stored in a struct which must live
/// for the `'static` lifetime:
///
/// ```
/// # use sharded_slab::Pool;
/// use sharded_slab::pool::OwnedRef;
/// use std::sync::Arc;
///
/// pub struct MyStruct {
/// pool_ref: OwnedRef<String>,
/// // ... other fields ...
/// }
///
/// // Suppose this is some arbitrary function which requires a value that
/// // lives for the 'static lifetime...
/// fn function_requiring_static<T: 'static>(t: &T) {
/// // ... do something extremely important and interesting ...
/// }
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let pool_ref = pool.clone().get_owned(key).unwrap();
/// let my_struct = MyStruct {
/// pool_ref,
/// // ...
/// };
///
/// // We can use `my_struct` anywhere where it is required to have the
/// // `'static` lifetime:
/// function_requiring_static(&my_struct);
/// ```
///
/// `OwnedRef`s may be sent between threads:
///
/// ```
/// # use sharded_slab::Pool;
/// use std::{thread, sync::Arc};
///
/// let pool: Arc<Pool<String>> = Arc::new(Pool::new());
/// let key = pool.create_with(|item| item.push_str("hello world")).unwrap();
///
/// // Look up the created `Key`, returning an `OwnedRef`.
/// let value = pool.clone().get_owned(key).unwrap();
///
/// thread::spawn(move || {
/// assert_eq!(value, String::from("hello world"));
/// // ...
/// }).join().unwrap();
/// ```
///
/// [`get`]: Pool::get
/// [`OwnedRef`]: crate::pool::OwnedRef
/// [`Ref`]: crate::pool::Ref
pub fn get_owned(self: Arc<Self>, key: usize) -> Option<OwnedRef<T, C>> {
let tid = C::unpack_tid(key);
test_println!("pool: get{:?}; current={:?}", tid, Tid::<C>::current());
let shard = self.shards.get(tid.as_usize())?;
let inner = shard.with_slot(key, |slot| slot.get(C::unpack_gen(key)))?;
Some(OwnedRef {
inner,
pool: self.clone(),
key,
})
}
/// Remove the value using the storage associated with the given key from the pool, returning
/// `true` if the value was removed.
///
/// This method does _not_ block the current thread until the value can be
/// cleared. Instead, if another thread is currently accessing that value, this marks it to be
/// cleared by that thread when it is done accessing that value.
///
/// # Examples
///
/// ```rust
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
///
/// // Check out an item from the pool.
/// let mut item = pool.create().unwrap();
/// let key = item.key();
/// item.push_str("hello world");
/// drop(item);
///
/// assert_eq!(pool.get(key).unwrap(), String::from("hello world"));
///
/// pool.clear(key);
/// assert!(pool.get(key).is_none());
/// ```
///
/// ```
/// # use sharded_slab::Pool;
/// let pool: Pool<String> = Pool::new();
///
/// let key = pool.create_with(|item| item.push_str("Hello world!")).unwrap();
///
/// // Clearing a key that doesn't exist in the `Pool` will return `false`
/// assert_eq!(pool.clear(key + 69420), false);
///
/// // Clearing a key that does exist returns `true`
/// assert!(pool.clear(key));
///
/// // Clearing a key that has previously been cleared will return `false`
/// assert_eq!(pool.clear(key), false);
/// ```
/// [`clear`]: #method.clear
pub fn clear(&self, key: usize) -> bool {
let tid = C::unpack_tid(key);
let shard = self.shards.get(tid.as_usize());
if tid.is_current() {
shard
.map(|shard| shard.mark_clear_local(key))
.unwrap_or(false)
} else {
shard
.map(|shard| shard.mark_clear_remote(key))
.unwrap_or(false)
}
}
}
unsafe impl<T, C> Send for Pool<T, C>
where
T: Send + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Sync for Pool<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
impl<T> Default for Pool<T>
where
T: Clear + Default,
{
fn default() -> Self {
Self::new()
}
}
impl<T, C> fmt::Debug for Pool<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pool")
.field("shards", &self.shards)
.field("config", &C::debug())
.finish()
}
}
// === impl Ref ===
impl<'a, T, C> Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
/// Returns the key used to access this guard
pub fn key(&self) -> usize {
self.key
}
#[inline]
fn value(&self) -> &T {
unsafe {
// Safety: calling `slot::Guard::value` is unsafe, since the `Guard`
// value contains a pointer to the slot that may outlive the slab
// containing that slot. Here, the `Ref` has a borrowed reference to
// the shard containing that slot, which ensures that the slot will
// not be dropped while this `Guard` exists.
self.inner.value()
}
}
}
impl<'a, T, C> std::ops::Deref for Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<'a, T, C> Drop for Ref<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop Ref: try clearing data");
let should_clear = unsafe {
// Safety: calling `slot::Guard::release` is unsafe, since the
// `Guard` value contains a pointer to the slot that may outlive the
// slab containing that slot. Here, the `Ref` guard owns a
// borrowed reference to the shard containing that slot, which
// ensures that the slot will not be dropped while this `Ref`
// exists.
self.inner.release()
};
if should_clear {
self.shard.clear_after_release(self.key);
}
}
}
impl<'a, T, C> fmt::Debug for Ref<'a, T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<'a, T, C> PartialEq<T> for Ref<'a, T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
// === impl GuardMut ===
impl<'a, T, C: cfg::Config> RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
/// Returns the key used to access the guard.
pub fn key(&self) -> usize {
self.key
}
/// Downgrades the mutable guard to an immutable guard, allowing access to
/// the pooled value from other threads.
///
/// ## Examples
///
/// ```
/// # use sharded_slab::Pool;
/// # use std::{sync::Arc, thread};
/// let pool = Arc::new(Pool::<String>::new());
///
/// let mut guard_mut = pool.clone().create_owned().unwrap();
/// let key = guard_mut.key();
/// guard_mut.push_str("Hello");
///
/// // The pooled string is currently borrowed mutably, so other threads
/// // may not access it.
/// let pool2 = pool.clone();
/// thread::spawn(move || {
/// assert!(pool2.get(key).is_none())
/// }).join().unwrap();
///
/// // Downgrade the guard to an immutable reference.
/// let guard = guard_mut.downgrade();
///
/// // Now, other threads may also access the pooled value.
/// let pool2 = pool.clone();
/// thread::spawn(move || {
/// let guard = pool2.get(key)
/// .expect("the item may now be referenced by other threads");
/// assert_eq!(guard, String::from("Hello"));
/// }).join().unwrap();
///
/// // We can still access the value immutably through the downgraded guard.
/// assert_eq!(guard, String::from("Hello"));
/// ```
pub fn downgrade(mut self) -> Ref<'a, T, C> {
let inner = unsafe { self.inner.downgrade() };
Ref {
inner,
shard: self.shard,
key: self.key,
}
}
#[inline]
fn value(&self) -> &T {
unsafe {
// Safety: we are holding a reference to the shard which keeps the
// pointed slot alive. The returned reference will not outlive
// `self`.
self.inner.value()
}
}
}
impl<'a, T, C: cfg::Config> std::ops::Deref for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<'a, T, C> std::ops::DerefMut for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
// Safety: we are holding a reference to the shard which keeps the
// pointed slot alive. The returned reference will not outlive `self`.
self.inner.value_mut()
}
}
}
impl<'a, T, C> Drop for RefMut<'a, T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!(" -> drop RefMut: try clearing data");
let should_clear = unsafe {
// Safety: we are holding a reference to the shard which keeps the
// pointed slot alive. The returned reference will not outlive `self`.
self.inner.release()
};
if should_clear {
self.shard.clear_after_release(self.key);
}
}
}
impl<'a, T, C> fmt::Debug for RefMut<'a, T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<'a, T, C> PartialEq<T> for RefMut<'a, T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
self.value().eq(other)
}
}
// === impl OwnedRef ===
impl<T, C> OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
/// Returns the key used to access this guard
pub fn key(&self) -> usize {
self.key
}
#[inline]
fn value(&self) -> &T {
unsafe {
// Safety: calling `slot::Guard::value` is unsafe, since the `Guard`
// value contains a pointer to the slot that may outlive the slab
// containing that slot. Here, the `Ref` has a borrowed reference to
// the shard containing that slot, which ensures that the slot will
// not be dropped while this `Guard` exists.
self.inner.value()
}
}
}
impl<T, C> std::ops::Deref for OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<T, C> Drop for OwnedRef<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop OwnedRef: try clearing data");
let should_clear = unsafe {
// Safety: calling `slot::Guard::release` is unsafe, since the
// `Guard` value contains a pointer to the slot that may outlive the
// slab containing that slot. Here, the `OwnedRef` owns an `Arc`
// clone of the pool, which keeps it alive as long as the `OwnedRef`
// exists.
self.inner.release()
};
if should_clear {
let shard_idx = Tid::<C>::from_packed(self.key);
test_println!("-> shard={:?}", shard_idx);
if let Some(shard) = self.pool.shards.get(shard_idx.as_usize()) {
shard.clear_after_release(self.key);
} else {
test_println!("-> shard={:?} does not exist! THIS IS A BUG", shard_idx);
debug_assert!(std::thread::panicking(), "[internal error] tried to drop an `OwnedRef` to a slot on a shard that never existed!");
}
}
}
}
impl<T, C> fmt::Debug for OwnedRef<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<T, C> PartialEq<T> for OwnedRef<T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
unsafe impl<T, C> Sync for OwnedRef<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Send for OwnedRef<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
// === impl OwnedRefMut ===
impl<T, C> OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
/// Returns the key used to access this guard
pub fn key(&self) -> usize {
self.key
}
/// Downgrades the owned mutable guard to an owned immutable guard, allowing
/// access to the pooled value from other threads.
///
/// ## Examples
///
/// ```
/// # use sharded_slab::Pool;
/// # use std::{sync::Arc, thread};
/// let pool = Arc::new(Pool::<String>::new());
///
/// let mut guard_mut = pool.clone().create_owned().unwrap();
/// let key = guard_mut.key();
/// guard_mut.push_str("Hello");
///
/// // The pooled string is currently borrowed mutably, so other threads
/// // may not access it.
/// let pool2 = pool.clone();
/// thread::spawn(move || {
/// assert!(pool2.get(key).is_none())
/// }).join().unwrap();
///
/// // Downgrade the guard to an immutable reference.
/// let guard = guard_mut.downgrade();
///
/// // Now, other threads may also access the pooled value.
/// let pool2 = pool.clone();
/// thread::spawn(move || {
/// let guard = pool2.get(key)
/// .expect("the item may now be referenced by other threads");
/// assert_eq!(guard, String::from("Hello"));
/// }).join().unwrap();
///
/// // We can still access the value immutably through the downgraded guard.
/// assert_eq!(guard, String::from("Hello"));
/// ```
pub fn downgrade(mut self) -> OwnedRef<T, C> {
let inner = unsafe { self.inner.downgrade() };
OwnedRef {
inner,
pool: self.pool.clone(),
key: self.key,
}
}
fn shard(&self) -> Option<&Shard<T, C>> {
let shard_idx = Tid::<C>::from_packed(self.key);
test_println!("-> shard={:?}", shard_idx);
self.pool.shards.get(shard_idx.as_usize())
}
#[inline]
fn value(&self) -> &T {
unsafe {
// Safety: calling `slot::InitGuard::value` is unsafe, since the `Guard`
// value contains a pointer to the slot that may outlive the slab
// containing that slot. Here, the `OwnedRefMut` has an `Arc` clone of
// the shard containing that slot, which ensures that the slot will
// not be dropped while this `Guard` exists.
self.inner.value()
}
}
}
impl<T, C> std::ops::Deref for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
type Target = T;
fn deref(&self) -> &Self::Target {
self.value()
}
}
impl<T, C> std::ops::DerefMut for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
// Safety: calling `slot::InitGuard::value_mut` is unsafe, since the
// `Guard` value contains a pointer to the slot that may outlive
// the slab containing that slot. Here, the `OwnedRefMut` has an
// `Arc` clone of the shard containing that slot, which ensures that
// the slot will not be dropped while this `Guard` exists.
self.inner.value_mut()
}
}
}
impl<T, C> Drop for OwnedRefMut<T, C>
where
T: Clear + Default,
C: cfg::Config,
{
fn drop(&mut self) {
test_println!("drop OwnedRefMut: try clearing data");
let should_clear = unsafe {
// Safety: calling `slot::Guard::release` is unsafe, since the
// `Guard` value contains a pointer to the slot that may outlive the
// slab containing that slot. Here, the `OwnedRefMut` owns an `Arc`
// clone of the pool, which keeps it alive as long as the
// `OwnedRefMut` exists.
self.inner.release()
};
if should_clear {
if let Some(shard) = self.shard() {
shard.clear_after_release(self.key);
} else {
test_println!("-> shard does not exist! THIS IS A BUG");
debug_assert!(std::thread::panicking(), "[internal error] tried to drop an `OwnedRefMut` to a slot on a shard that never existed!");
}
}
}
}
impl<T, C> fmt::Debug for OwnedRefMut<T, C>
where
T: fmt::Debug + Clear + Default,
C: cfg::Config,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.value(), f)
}
}
impl<T, C> PartialEq<T> for OwnedRefMut<T, C>
where
T: PartialEq<T> + Clear + Default,
C: cfg::Config,
{
fn eq(&self, other: &T) -> bool {
*self.value() == *other
}
}
unsafe impl<T, C> Sync for OwnedRefMut<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}
unsafe impl<T, C> Send for OwnedRefMut<T, C>
where
T: Sync + Clear + Default,
C: cfg::Config,
{
}