1use std::{collections::HashMap, hash::Hash, mem, sync::Arc};
5
6use reifydb_value::Result;
7use serde::{Serialize, de::DeserializeOwned};
8
9use crate::{
10 encoded::key::{EncodedKey, IntoEncodedKey},
11 util::lru::slab::SlabLru,
12 window::store::WindowStore,
13};
14
15#[derive(Clone, Copy, Debug)]
16pub enum StateBackend {
17 Data,
18
19 Internal,
20}
21
22pub struct StateCache<K, V> {
23 cache: SlabLru<K, Arc<V>>,
24 dirty: HashMap<K, Option<Arc<V>>>,
25 backend: StateBackend,
26}
27
28impl<K, V> StateCache<K, V>
29where
30 K: Hash + Eq + Clone,
31 for<'a> &'a K: IntoEncodedKey,
32 V: Clone + Serialize + DeserializeOwned,
33{
34 pub fn new(capacity: usize) -> Self {
35 Self::with_backend(capacity, StateBackend::Data)
36 }
37
38 pub fn new_internal(capacity: usize) -> Self {
39 Self::with_backend(capacity, StateBackend::Internal)
40 }
41
42 fn with_backend(capacity: usize, backend: StateBackend) -> Self {
43 Self {
44 cache: SlabLru::new(capacity),
45 dirty: HashMap::new(),
46 backend,
47 }
48 }
49
50 pub fn get_arc(&mut self, store: &mut impl WindowStore, key: &K) -> Result<Option<Arc<V>>> {
51 if let Some(cached) = self.cache.get(key) {
52 return Ok(Some(cached));
53 }
54
55 if let Some(slot) = self.dirty.get(key) {
56 return Ok(slot.clone());
57 }
58
59 let encoded_key = key.into_encoded_key();
60 let loaded = match self.backend {
61 StateBackend::Data => store.state_get::<V>(&encoded_key)?,
62 StateBackend::Internal => store.internal_get::<V>(&encoded_key)?,
63 };
64 match loaded {
65 Some(value) => {
66 let arc = Arc::new(value);
67 self.cache.put(key.clone(), arc.clone());
68 Ok(Some(arc))
69 }
70 None => Ok(None),
71 }
72 }
73
74 pub fn get(&mut self, store: &mut impl WindowStore, key: &K) -> Result<Option<V>> {
75 Ok(self.get_arc(store, key)?.map(|arc| (*arc).clone()))
76 }
77
78 pub fn warm(&mut self, store: &mut impl WindowStore, keys: &[K]) -> Result<()> {
79 let mut to_load: Vec<K> = Vec::new();
80 for key in keys {
81 if self.cache.contains_key(key) || self.dirty.contains_key(key) {
82 continue;
83 }
84 to_load.push(key.clone());
85 }
86 if to_load.is_empty() {
87 return Ok(());
88 }
89
90 let mut by_encoded: HashMap<Vec<u8>, K> = HashMap::with_capacity(to_load.len());
91 let mut encoded_keys: Vec<EncodedKey> = Vec::with_capacity(to_load.len());
92 for key in &to_load {
93 let encoded = key.into_encoded_key();
94 by_encoded.insert(encoded.as_bytes().to_vec(), key.clone());
95 encoded_keys.push(encoded);
96 }
97
98 let cache = &mut self.cache;
99 let mut visit = |encoded: EncodedKey, value: V| -> Result<()> {
100 if let Some(key) = by_encoded.get(encoded.as_bytes()) {
101 cache.put(key.clone(), Arc::new(value));
102 }
103 Ok(())
104 };
105 match self.backend {
106 StateBackend::Data => store.state_get_many_visit::<V>(&encoded_keys, &mut visit)?,
107 StateBackend::Internal => store.internal_get_many_visit::<V>(&encoded_keys, &mut visit)?,
108 }
109 Ok(())
110 }
111
112 pub fn set(&mut self, _store: &mut impl WindowStore, key: &K, value: &V) -> Result<()> {
113 let arc = Arc::new(value.clone());
114 self.cache.put(key.clone(), arc.clone());
115 self.dirty.insert(key.clone(), Some(arc));
116 Ok(())
117 }
118
119 pub fn put(&mut self, _store: &mut impl WindowStore, key: &K, value: V) -> Result<()> {
120 let arc = Arc::new(value);
121 self.cache.put(key.clone(), arc.clone());
122 self.dirty.insert(key.clone(), Some(arc));
123 Ok(())
124 }
125
126 pub fn put_arc(&mut self, _store: &mut impl WindowStore, key: &K, value: Arc<V>) -> Result<()> {
127 self.cache.put(key.clone(), value.clone());
128 self.dirty.insert(key.clone(), Some(value));
129 Ok(())
130 }
131
132 pub fn modify<F>(&mut self, store: &mut impl WindowStore, key: &K, f: F) -> Result<()>
133 where
134 F: FnOnce(&mut V) -> Result<()>,
135 V: Default,
136 {
137 let mut arc = self.get_arc(store, key)?.unwrap_or_else(|| Arc::new(V::default()));
138 f(Arc::make_mut(&mut arc))?;
139 self.put_arc(store, key, arc)
140 }
141
142 pub fn remove(&mut self, _store: &mut impl WindowStore, key: &K) -> Result<()> {
143 self.cache.remove(key);
144 self.dirty.insert(key.clone(), None);
145 Ok(())
146 }
147
148 pub fn flush(&mut self, store: &mut impl WindowStore) -> Result<()> {
149 let dirty = mem::take(&mut self.dirty);
150 for (key, slot) in dirty {
151 let encoded_key = (&key).into_encoded_key();
152 match (slot, self.backend) {
153 (Some(value), StateBackend::Data) => store.state_set(&encoded_key, value.as_ref())?,
154 (Some(value), StateBackend::Internal) => {
155 store.internal_set(&encoded_key, value.as_ref())?
156 }
157 (None, StateBackend::Data) => store.state_drop(&encoded_key)?,
158 (None, StateBackend::Internal) => store.internal_drop(&encoded_key)?,
159 }
160 }
161 Ok(())
162 }
163
164 pub fn clear_cache(&mut self) {
165 self.cache.clear();
166 }
167
168 pub fn invalidate(&mut self, key: &K) {
169 self.cache.remove(key);
170 }
171
172 pub fn is_cached(&self, key: &K) -> bool {
173 self.cache.contains_key(key)
174 }
175
176 pub fn len(&self) -> usize {
177 self.cache.len()
178 }
179
180 pub fn is_empty(&self) -> bool {
181 self.cache.is_empty()
182 }
183
184 pub fn capacity(&self) -> usize {
185 self.cache.capacity()
186 }
187}
188
189impl<K, V> StateCache<K, V>
190where
191 K: Hash + Eq + Clone,
192 for<'a> &'a K: IntoEncodedKey,
193 V: Clone + Default + Serialize + DeserializeOwned,
194{
195 pub fn get_or_default(&mut self, store: &mut impl WindowStore, key: &K) -> Result<V> {
196 match self.get(store, key)? {
197 Some(value) => Ok(value),
198 None => Ok(V::default()),
199 }
200 }
201
202 pub fn update<U>(&mut self, store: &mut impl WindowStore, key: &K, updater: U) -> Result<V>
203 where
204 U: FnOnce(&mut V) -> Result<()>,
205 {
206 let mut value = self.get_or_default(store, key)?;
207 updater(&mut value)?;
208 self.set(store, key, &value)?;
209 Ok(value)
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use std::{collections::HashMap, ops::Bound};
216
217 use postcard::{from_bytes, to_allocvec};
218 use reifydb_value::value::row_number::RowNumber;
219
220 use super::*;
221 use crate::encoded::key::EncodedKeyRange;
222
223 #[derive(Default)]
224 struct MockStore {
225 data: HashMap<Vec<u8>, Vec<u8>>,
226 internal: HashMap<Vec<u8>, Vec<u8>>,
227 }
228
229 impl WindowStore for MockStore {
230 fn state_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
231 Ok(self.data.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
232 }
233 fn state_get_many_visit<V: DeserializeOwned>(
234 &mut self,
235 keys: &[EncodedKey],
236 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
237 ) -> Result<()> {
238 for key in keys {
239 if let Some(b) = self.data.get(key.as_bytes()) {
240 visit(key.clone(), from_bytes(b).expect("decode"))?;
241 }
242 }
243 Ok(())
244 }
245 fn state_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
246 self.data.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
247 Ok(())
248 }
249 fn state_remove(&mut self, key: &EncodedKey) -> Result<()> {
250 self.data.remove(key.as_bytes());
251 Ok(())
252 }
253 fn state_drop(&mut self, key: &EncodedKey) -> Result<()> {
254 self.data.remove(key.as_bytes());
255 Ok(())
256 }
257 fn internal_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
258 Ok(self.internal.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
259 }
260 fn internal_get_many_visit<V: DeserializeOwned>(
261 &mut self,
262 keys: &[EncodedKey],
263 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
264 ) -> Result<()> {
265 for key in keys {
266 if let Some(b) = self.internal.get(key.as_bytes()) {
267 visit(key.clone(), from_bytes(b).expect("decode"))?;
268 }
269 }
270 Ok(())
271 }
272 fn internal_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
273 self.internal.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
274 Ok(())
275 }
276 fn internal_remove(&mut self, key: &EncodedKey) -> Result<()> {
277 self.internal.remove(key.as_bytes());
278 Ok(())
279 }
280 fn internal_drop(&mut self, key: &EncodedKey) -> Result<()> {
281 self.internal.remove(key.as_bytes());
282 Ok(())
283 }
284 fn internal_range_visit<V: DeserializeOwned>(
285 &mut self,
286 range: EncodedKeyRange,
287 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
288 ) -> Result<()> {
289 let after_start = |k: &[u8]| match &range.start {
290 Bound::Included(s) => k >= s.as_bytes(),
291 Bound::Excluded(s) => k > s.as_bytes(),
292 Bound::Unbounded => true,
293 };
294 let before_end = |k: &[u8]| match &range.end {
295 Bound::Included(e) => k <= e.as_bytes(),
296 Bound::Excluded(e) => k < e.as_bytes(),
297 Bound::Unbounded => true,
298 };
299 let mut matched: Vec<(Vec<u8>, Vec<u8>)> = self
300 .internal
301 .iter()
302 .filter(|(k, _)| after_start(k) && before_end(k))
303 .map(|(k, v)| (k.clone(), v.clone()))
304 .collect();
305 matched.sort_by(|a, b| a.0.cmp(&b.0));
306 for (k, b) in matched {
307 visit(EncodedKey::new(k), from_bytes(&b).expect("decode"))?;
308 }
309 Ok(())
310 }
311 fn get_or_create_row_number(&mut self, _key: &EncodedKey) -> Result<(RowNumber, bool)> {
312 Ok((RowNumber(1), true))
313 }
314 fn get_or_create_row_numbers(&mut self, keys: &[EncodedKey]) -> Result<Vec<(RowNumber, bool)>> {
315 Ok(keys.iter().enumerate().map(|(i, _)| (RowNumber(i as u64 + 1), true)).collect())
316 }
317 fn allocate_row_numbers(&mut self, _count: u64) -> Result<RowNumber> {
318 Ok(RowNumber(1))
319 }
320 fn clock_now_nanos(&self) -> u64 {
321 0
322 }
323 }
324
325 #[test]
326 fn set_then_flush_persists_to_store_and_survives_cache_clear() {
327 let mut store = MockStore::default();
328 let mut cache: StateCache<String, i32> = StateCache::new(100);
329
330 cache.set(&mut store, &"a".to_string(), &7).unwrap();
332 assert_eq!(cache.get(&mut store, &"a".to_string()).unwrap(), Some(7));
333 assert!(store.data.is_empty());
335
336 cache.flush(&mut store).unwrap();
337 assert!(!store.data.is_empty(), "flush must write dirty entries to the store");
338
339 cache.clear_cache();
341 assert_eq!(cache.get(&mut store, &"a".to_string()).unwrap(), Some(7));
342 }
343
344 #[test]
345 fn warm_bulk_loads_present_keys_and_skips_absent() {
346 let mut store = MockStore::default();
347 {
348 let mut seed: StateCache<String, i32> = StateCache::new(100);
349 seed.set(&mut store, &"a".to_string(), &1).unwrap();
350 seed.set(&mut store, &"b".to_string(), &2).unwrap();
351 seed.flush(&mut store).unwrap();
352 }
353
354 let mut cache: StateCache<String, i32> = StateCache::new(100);
355 let keys = vec!["a".to_string(), "b".to_string(), "missing".to_string()];
356 cache.warm(&mut store, &keys).unwrap();
357
358 assert!(cache.is_cached(&"a".to_string()));
359 assert!(cache.is_cached(&"b".to_string()));
360 assert!(!cache.is_cached(&"missing".to_string()));
361 }
362
363 #[test]
364 fn dirty_write_shadows_committed_value_during_warm() {
365 let mut store = MockStore::default();
366 {
367 let mut seed: StateCache<String, i32> = StateCache::new(100);
368 seed.set(&mut store, &"a".to_string(), &1).unwrap();
369 seed.flush(&mut store).unwrap();
370 }
371
372 let mut cache: StateCache<String, i32> = StateCache::new(100);
373 cache.set(&mut store, &"a".to_string(), &99).unwrap();
374 cache.warm(&mut store, &["a".to_string()]).unwrap();
375 assert_eq!(
376 cache.get(&mut store, &"a".to_string()).unwrap(),
377 Some(99),
378 "pending write must shadow store"
379 );
380 }
381
382 #[test]
383 fn internal_backend_round_trips_through_internal_store() {
384 let mut store = MockStore::default();
385 let mut cache: StateCache<String, i32> = StateCache::new_internal(100);
386 cache.set(&mut store, &"a".to_string(), &5).unwrap();
387 cache.flush(&mut store).unwrap();
388 assert!(store.data.is_empty(), "internal backend must not write to the data store");
389 assert!(!store.internal.is_empty(), "internal backend must write to the internal store");
390 cache.clear_cache();
391 assert_eq!(cache.get(&mut store, &"a".to_string()).unwrap(), Some(5));
392 }
393}