Skip to main content

dualcache_ff/core/
static_cache.rs

1use crate::core::engine::DualCacheCore;
2use crate::componant::qsbr::{ThreadStateNode, pin};
3use crate::componant::config::CachePolicy;
4use core::hash::Hash;
5use no_std_tool::sync::SpinMutex;
6use ::core::sync::atomic::{AtomicUsize, Ordering};
7
8pub struct StaticDualCache<K, V, P: CachePolicy, const T0_CAP: usize, const T1_CAP: usize, const T2_CAP: usize, const TOTAL_CAP: usize> {
9    inner: SpinMutex<(DualCacheCore<K, V, P, T0_CAP, T1_CAP, T2_CAP, TOTAL_CAP>, ThreadStateNode, bool)>,
10    insert_count: AtomicUsize,
11}
12
13impl<K, V, P: CachePolicy, const T0_CAP: usize, const T1_CAP: usize, const T2_CAP: usize, const TOTAL_CAP: usize> StaticDualCache<K, V, P, T0_CAP, T1_CAP, T2_CAP, TOTAL_CAP> 
14where
15    K: Clone + Eq + Hash,
16    V: Clone,
17{
18    pub const fn new(eviction: P::Evict) -> Self {
19        Self {
20            inner: SpinMutex::new((DualCacheCore::new(eviction), ThreadStateNode::new(), false)),
21            insert_count: AtomicUsize::new(0),
22        }
23    }
24
25    /// Retrieve a value from the cache synchronously.
26    pub fn get(&self, key: &K) -> Option<V> {
27        let mut inner = match self.inner.lock() {
28            Ok(guard) => guard,
29            Err(_) => return None, // Aerospace-grade: treat lock timeout as cache miss to guarantee bounded latency
30        };
31        let (engine, qsbr_node, registered) = &mut *inner;
32        
33        if !*registered {
34            crate::componant::qsbr::register_node(qsbr_node as *mut _);
35            *registered = true;
36        }
37        
38        let guard = pin(qsbr_node as *mut ThreadStateNode);
39        
40        // Map the reference to an owned value to allow releasing the lock safely
41        // Pass 16 to force record_hit for static cache which doesn't have a thread local op_count
42        engine.get(key, &guard, 16).map(|(v_ref, _tier, _hint)| v_ref.clone())
43    }
44
45    /// Insert a key-value pair into the cache. Handles inline reclamation synchronously.
46    pub fn put(&self, key: K, value: V) {
47        let mut inner = match self.inner.lock() {
48            Ok(guard) => guard,
49            Err(_) => return, // Aerospace-grade: drop insert on lock timeout to guarantee bounded latency
50        };
51        let (engine, qsbr_node, registered) = &mut *inner;
52        
53        if !*registered {
54            crate::componant::qsbr::register_node(qsbr_node as *mut _);
55            *registered = true;
56        }
57        
58        let node_ptr = qsbr_node as *mut ThreadStateNode;
59        
60        engine.put(key, value, node_ptr);
61        
62        let count = self.insert_count.fetch_add(1, Ordering::Relaxed);
63        
64        // Inline QSBR reclamation every 1024 inserts to prevent Arena OOM
65        if count % 1024 == 1023 {
66            engine.sync_reclaim();
67        }
68    }
69}
70
71impl<K, V, P: CachePolicy, const T0_CAP: usize, const T1_CAP: usize, const T2_CAP: usize, const TOTAL_CAP: usize> Default for StaticDualCache<K, V, P, T0_CAP, T1_CAP, T2_CAP, TOTAL_CAP> 
72where
73    K: Clone + Eq + Hash,
74    V: Clone,
75{
76    fn default() -> Self {
77        Self::new(P::Evict::default())
78    }
79}
80
81/// A default configured Bottom-Up Anchoring StaticDualCache
82pub type StaticBottomUpCache<K, V> = StaticDualCache<K, V, crate::componant::config::DefaultExponentialPolicy, 64, 4096, 262144, { 64 + 4096 + 262144 }>;