reifydb_cdc/compact/
cache.rs1use std::sync::Arc;
5
6use reifydb_core::{common::CommitVersion, interface::cdc::Cdc};
7use reifydb_runtime::cache::sync::SyncLru;
8
9#[derive(Clone)]
10pub struct BlockCache {
11 inner: Arc<SyncLru<CommitVersion, Arc<Vec<Cdc>>>>,
12}
13
14impl BlockCache {
15 pub const DEFAULT_CAPACITY: usize = 8;
16
17 pub fn new(capacity: usize) -> Self {
18 Self {
19 inner: Arc::new(SyncLru::new(capacity.max(1))),
20 }
21 }
22
23 pub fn capacity(&self) -> usize {
24 self.inner.capacity()
25 }
26
27 pub fn get(&self, key: CommitVersion) -> Option<Arc<Vec<Cdc>>> {
28 self.inner.get(&key)
29 }
30
31 pub fn put(&self, key: CommitVersion, value: Arc<Vec<Cdc>>) {
32 let _ = self.inner.put(key, value);
33 }
34
35 pub fn remove(&self, key: CommitVersion) {
36 let _ = self.inner.remove(&key);
37 }
38
39 pub fn clear(&self) {
40 self.inner.clear();
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 fn cv(n: u64) -> CommitVersion {
49 CommitVersion(n)
50 }
51
52 fn empty_block() -> Arc<Vec<Cdc>> {
53 Arc::new(Vec::new())
54 }
55
56 #[test]
57 fn put_then_get_returns_inserted_arc() {
58 let cache = BlockCache::new(4);
59 let block = empty_block();
60 cache.put(cv(1), block.clone());
61
62 let got = cache.get(cv(1)).expect("entry should be present");
63 assert!(Arc::ptr_eq(&got, &block));
64 }
65
66 #[test]
67 fn get_returns_none_for_missing_key() {
68 let cache = BlockCache::new(4);
69 assert!(cache.get(cv(1)).is_none());
70
71 cache.put(cv(1), empty_block());
72 assert!(cache.get(cv(2)).is_none());
73 }
74
75 #[test]
76 fn put_overwrites_existing_value() {
77 let cache = BlockCache::new(4);
78 let first = empty_block();
79 let second = empty_block();
80 assert!(!Arc::ptr_eq(&first, &second));
81
82 cache.put(cv(1), first);
83 cache.put(cv(1), second.clone());
84
85 let got = cache.get(cv(1)).expect("entry should be present");
86 assert!(Arc::ptr_eq(&got, &second));
87 }
88
89 #[test]
90 fn remove_drops_value() {
91 let cache = BlockCache::new(4);
92 cache.put(cv(1), empty_block());
93
94 cache.remove(cv(1));
95 assert!(cache.get(cv(1)).is_none());
96 }
97
98 #[test]
99 fn remove_missing_key_is_noop() {
100 let cache = BlockCache::new(4);
101 cache.remove(cv(99));
102
103 cache.put(cv(1), empty_block());
104 cache.remove(cv(99));
105 assert!(cache.get(cv(1)).is_some());
106 }
107
108 #[test]
109 fn clear_empties_cache() {
110 let cache = BlockCache::new(4);
111 cache.put(cv(1), empty_block());
112 cache.put(cv(2), empty_block());
113 cache.put(cv(3), empty_block());
114
115 cache.clear();
116
117 assert!(cache.get(cv(1)).is_none());
118 assert!(cache.get(cv(2)).is_none());
119 assert!(cache.get(cv(3)).is_none());
120 }
121
122 #[test]
123 fn eviction_drops_least_recently_used() {
124 let cache = BlockCache::new(2);
125 cache.put(cv(1), empty_block());
126 cache.put(cv(2), empty_block());
127 cache.put(cv(3), empty_block());
128 cache.inner.run_pending_tasks();
129
130 assert!(cache.get(cv(1)).is_none(), "oldest entry should be evicted");
131 assert!(cache.get(cv(2)).is_some());
132 assert!(cache.get(cv(3)).is_some());
133 }
134
135 #[test]
136 fn get_promotes_recency_so_old_key_survives() {
137 let cache = BlockCache::new(2);
138 cache.put(cv(1), empty_block());
139 cache.put(cv(2), empty_block());
140 cache.inner.run_pending_tasks();
141
142 let _ = cache.get(cv(1));
143 cache.inner.run_pending_tasks();
144
145 cache.put(cv(3), empty_block());
146 cache.inner.run_pending_tasks();
147
148 assert!(cache.get(cv(1)).is_some(), "recently-touched key should survive");
149 assert!(cache.get(cv(2)).is_none(), "untouched older key should be evicted");
150 assert!(cache.get(cv(3)).is_some());
151 }
152
153 #[test]
154 fn new_with_zero_capacity_is_clamped_and_usable() {
155 let cache = BlockCache::new(0);
156 cache.put(cv(1), empty_block());
157 assert!(cache.get(cv(1)).is_some());
158 }
159
160 #[test]
161 fn clone_shares_backing_storage() {
162 let a = BlockCache::new(4);
163 let b = a.clone();
164
165 let block = empty_block();
166 a.put(cv(1), block.clone());
167
168 let got = b.get(cv(1)).expect("clone should see writes from original");
169 assert!(Arc::ptr_eq(&got, &block));
170 }
171}