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