//! This module implements a map that can be modified from only one task but read from many others. //! //! We ensure this map avoids race conditions from multiple writers by doing these two things: //! - We only allow writing from one owner of the `&mut self` [`ConcurrentReadMap`]. //! It cannot be cloned. //! - The read-only replicas [`ReadOnlyMap`] can only read, not write, but allow reading from //! concurrent tasks. use std::{hash::Hash, sync::Arc}; use rustc_hash::FxBuildHasher; /// A map that can be modified from only one task but read from many others. /// /// Only the single `&mut self`-based "leader" which owns this map can modify it, but cheaply /// clonable "followers" can be created with [`ConcurrentReadMap::read_only`]. /// These clones will update with recent writes from the leader. #[derive(Debug)] pub(crate) struct ConcurrentReadMap(Arc>); impl Default for ConcurrentReadMap { fn default() -> Self { Self(Default::default()) } } impl ConcurrentReadMap { pub(crate) fn get_or_insert_with(&mut self, key: K, f: F) -> V where F: FnOnce() -> V, V: Clone, { self.0.get_or_insert_with(key, f, &self.0.guard()).clone() } pub(crate) fn insert(&mut self, key: K, value: V) { self.0.insert(key, value, &self.0.guard()); } pub(crate) fn remove(&mut self, key: &K) { self.0.remove(key, &self.0.guard()); } pub(crate) fn read_only(&self) -> ReadOnlyMap { ReadOnlyMap(self.0.clone()) } } /// A read replica for a [`ConcurrentReadMap`]. /// /// These can be cloned cheaply and will read recent writes from the original map. #[derive(Clone, Debug)] pub(crate) struct ReadOnlyMap(Arc>); impl ReadOnlyMap { pub(crate) fn get(&self, key: &K) -> Option where V: Clone, { self.0.get(key, &self.0.guard()).cloned() } pub(crate) fn guard(&self) -> papaya::LocalGuard<'_> { self.0.guard() } pub(crate) fn values<'g, G: papaya::Guard>(&self, guard: &'g G) -> papaya::Values<'g, K, V, G> { self.0.values(guard) } }