//! 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 = 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 = 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 = 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 where T: Clear + Default, C: cfg::Config, { shards: shard::Array, _cfg: PhantomData, } /// 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, shard: &'a Shard, 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, shard: &'a Shard, 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> = 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, /// // ... other fields ... /// } /// /// // Suppose this is some arbitrary function which requires a value that /// // lives for the 'static lifetime... /// fn function_requiring_static(t: &T) { /// // ... do something extremely important and interesting ... /// } /// /// let pool: Arc> = 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> = 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 where T: Clear + Default, C: cfg::Config, { inner: page::slot::Guard, pool: Arc>, key: usize, } /// An owned guard that allows exclusive, mutable access to an object in a pool. /// /// An `OwnedRefMut` functions more or less identically to an owned /// `Box`: 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`, 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> = 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> = 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, /// // ... other fields ... /// } /// /// // Suppose this is some arbitrary function which requires a value that /// // lives for the 'static lifetime... /// fn function_requiring_static(t: &T) { /// // ... do something extremely important and interesting ... /// } /// /// let pool: Arc> = 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> = 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> = 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 where T: Clear + Default, C: cfg::Config, { inner: page::slot::InitGuard, pool: Arc>, key: usize, } impl Pool 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() -> Pool { C::validate(); Pool { shards: shard::Array::new(), _cfg: PhantomData, } } } impl Pool 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 = 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> { 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` functions more or less identically to an owned /// `Box`: 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`, 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> = 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> = 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, /// // ... other fields ... /// } /// /// // Suppose this is some arbitrary function which requires a value that /// // lives for the 'static lifetime... /// fn function_requiring_static(t: &T) { /// // ... do something extremely important and interesting ... /// } /// /// let pool: Arc> = 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> = 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> = 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) -> Option> { 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 = 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 { 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 = 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> { let tid = C::unpack_tid(key); test_println!("pool: get{:?}; current={:?}", tid, Tid::::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> = 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, /// // ... other fields ... /// } /// /// // Suppose this is some arbitrary function which requires a value that /// // lives for the 'static lifetime... /// fn function_requiring_static(t: &T) { /// // ... do something extremely important and interesting ... /// } /// /// let pool: Arc> = 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> = 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, key: usize) -> Option> { let tid = C::unpack_tid(key); test_println!("pool: get{:?}; current={:?}", tid, Tid::::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 = 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 = 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 Send for Pool where T: Send + Clear + Default, C: cfg::Config, { } unsafe impl Sync for Pool where T: Sync + Clear + Default, C: cfg::Config, { } impl Default for Pool where T: Clear + Default, { fn default() -> Self { Self::new() } } impl fmt::Debug for Pool 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 for Ref<'a, T, C> where T: PartialEq + 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::::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 for RefMut<'a, T, C> where T: PartialEq + Clear + Default, C: cfg::Config, { fn eq(&self, other: &T) -> bool { self.value().eq(other) } } // === impl OwnedRef === impl OwnedRef 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 std::ops::Deref for OwnedRef where T: Clear + Default, C: cfg::Config, { type Target = T; fn deref(&self) -> &Self::Target { self.value() } } impl Drop for OwnedRef 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::::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 fmt::Debug for OwnedRef 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 PartialEq for OwnedRef where T: PartialEq + Clear + Default, C: cfg::Config, { fn eq(&self, other: &T) -> bool { *self.value() == *other } } unsafe impl Sync for OwnedRef where T: Sync + Clear + Default, C: cfg::Config, { } unsafe impl Send for OwnedRef where T: Sync + Clear + Default, C: cfg::Config, { } // === impl OwnedRefMut === impl OwnedRefMut 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::::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 { let inner = unsafe { self.inner.downgrade() }; OwnedRef { inner, pool: self.pool.clone(), key: self.key, } } fn shard(&self) -> Option<&Shard> { let shard_idx = Tid::::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 std::ops::Deref for OwnedRefMut where T: Clear + Default, C: cfg::Config, { type Target = T; fn deref(&self) -> &Self::Target { self.value() } } impl std::ops::DerefMut for OwnedRefMut 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 Drop for OwnedRefMut 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 fmt::Debug for OwnedRefMut 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 PartialEq for OwnedRefMut where T: PartialEq + Clear + Default, C: cfg::Config, { fn eq(&self, other: &T) -> bool { *self.value() == *other } } unsafe impl Sync for OwnedRefMut where T: Sync + Clear + Default, C: cfg::Config, { } unsafe impl Send for OwnedRefMut where T: Sync + Clear + Default, C: cfg::Config, { }