Skip to main content

fast_cache/storage/
embedded_store_shared.rs

1use std::array;
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4use std::sync::Arc;
5
6use bytes::Bytes as SharedBytes;
7use crossbeam_utils::CachePadded;
8use parking_lot::{
9    RwLock as FairRwLock, RwLockReadGuard as FairRwLockReadGuard,
10    RwLockWriteGuard as FairRwLockWriteGuard,
11};
12use rblock::{
13    RwLock as ReadBiasedRwLock, RwLockReadGuard as ReadBiasedRwLockReadGuard,
14    RwLockWriteGuard as ReadBiasedRwLockWriteGuard,
15};
16
17use crate::config::EvictionPolicy;
18use crate::storage::embedded_store::{
19    EmbeddedKeyRoute, EmbeddedRouteMode, EmbeddedSessionRoute, EmbeddedShard,
20    assert_valid_shard_count, compute_key_route, compute_session_shard, shift_for,
21};
22use crate::storage::{hash_key, ttl_now_millis};
23
24/// Lock policy for [`SharedEmbeddedStore`] stripes.
25///
26/// `ReadBiased` favors read-heavy cache workloads by allowing new readers to
27/// enter while a writer is waiting. `Fair` uses `parking_lot::RwLock`, which is
28/// a better fit when writes are frequent or write latency matters more than
29/// peak read-side throughput.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum SharedEmbeddedLockPolicy {
32    /// Favor readers. Best for read-heavy shared-handle workloads.
33    ReadBiased,
34    /// Favor bounded writer progress. Best for write-heavy or skewed workloads.
35    Fair,
36}
37
38fn default_lock_policy() -> SharedEmbeddedLockPolicy {
39    if cfg!(feature = "shared-parking-lot-lock") {
40        SharedEmbeddedLockPolicy::Fair
41    } else {
42        SharedEmbeddedLockPolicy::ReadBiased
43    }
44}
45
46/// Configuration for [`SharedEmbeddedStore`].
47#[derive(Debug, Clone)]
48pub struct SharedEmbeddedConfig {
49    /// Total memory budget for all stripes. `None` disables memory-limit eviction.
50    pub total_memory_bytes: Option<usize>,
51    /// Eviction policy applied independently inside each stripe.
52    pub eviction_policy: EvictionPolicy,
53    /// Key routing mode used by point and session APIs.
54    pub route_mode: EmbeddedRouteMode,
55    /// Approximate total point-key capacity to reserve across all stripes.
56    pub flat_map_capacity_hint: Option<usize>,
57    /// Lock policy used by each stripe.
58    pub lock_policy: SharedEmbeddedLockPolicy,
59}
60
61impl Default for SharedEmbeddedConfig {
62    fn default() -> Self {
63        Self {
64            total_memory_bytes: None,
65            eviction_policy: EvictionPolicy::None,
66            route_mode: EmbeddedRouteMode::FullKey,
67            flat_map_capacity_hint: None,
68            lock_policy: default_lock_policy(),
69        }
70    }
71}
72
73/// Cloneable, lock-striped embedded cache handle.
74///
75/// `SharedEmbeddedStore` is the embedded mode for applications that want to
76/// clone one cache handle into many workers while still allowing each worker to
77/// reach every key. It uses the same `EmbeddedShard` storage primitive as
78/// [`crate::storage::EmbeddedStore`], but stores stripes in an `Arc` so clones
79/// are cheap and route to cache-padded shard locks.
80///
81/// ```compile_fail
82/// use fast_cache::storage::{SharedEmbeddedConfig, SharedEmbeddedStore};
83///
84/// let _ = SharedEmbeddedStore::<3>::new(SharedEmbeddedConfig::default());
85/// ```
86#[derive(Debug)]
87pub struct SharedEmbeddedStore<const SHARDS: usize> {
88    inner: Arc<SharedInner<SHARDS>>,
89}
90
91#[derive(Debug)]
92struct SharedInner<const SHARDS: usize> {
93    shards: [CachePadded<SharedShardLock<EmbeddedShard>>; SHARDS],
94    shift: u32,
95    route_mode: EmbeddedRouteMode,
96}
97mod core;
98mod guards;
99mod lock;
100mod point;
101mod session;
102#[cfg(test)]
103mod tests;
104
105pub use guards::{Entry, Ref, RefMut, VacantEntry};
106use lock::{SharedReadGuard, SharedShardLock, SharedWriteGuard};