subms_block_cache/features/
arc.rs1use std::collections::HashMap;
23use std::hash::Hash;
24
25#[derive(Clone, Copy, PartialEq, Eq, Debug)]
27enum List {
28 T1,
29 T2,
30 B1,
31 B2,
32}
33
34struct Node<K, V> {
35 key: K,
36 value: Option<V>,
38 prev: u32,
39 next: u32,
40 list: List,
41}
42
43const NIL: u32 = u32::MAX;
44
45pub struct ArcCache<K, V> {
49 c: usize,
50 p: usize,
51 nodes: Vec<Option<Node<K, V>>>,
52 free: Vec<u32>,
53 index: HashMap<K, u32>,
54 t1_head: u32,
56 t1_tail: u32,
57 t1_len: usize,
58 t2_head: u32,
59 t2_tail: u32,
60 t2_len: usize,
61 b1_head: u32,
62 b1_tail: u32,
63 b1_len: usize,
64 b2_head: u32,
65 b2_tail: u32,
66 b2_len: usize,
67}
68
69impl<K: Hash + Eq + Clone, V> ArcCache<K, V> {
70 pub fn with_capacity(c: usize) -> Self {
71 let c = c.max(1);
72 Self {
73 c,
74 p: 0,
75 nodes: Vec::new(),
76 free: Vec::new(),
77 index: HashMap::new(),
78 t1_head: NIL,
79 t1_tail: NIL,
80 t1_len: 0,
81 t2_head: NIL,
82 t2_tail: NIL,
83 t2_len: 0,
84 b1_head: NIL,
85 b1_tail: NIL,
86 b1_len: 0,
87 b2_head: NIL,
88 b2_tail: NIL,
89 b2_len: 0,
90 }
91 }
92
93 pub fn capacity(&self) -> usize {
94 self.c
95 }
96 pub fn len(&self) -> usize {
97 self.t1_len + self.t2_len
98 }
99 pub fn is_empty(&self) -> bool {
100 self.len() == 0
101 }
102 pub fn p(&self) -> usize {
103 self.p
104 }
105 pub fn t1_len(&self) -> usize {
106 self.t1_len
107 }
108 pub fn t2_len(&self) -> usize {
109 self.t2_len
110 }
111 pub fn b1_len(&self) -> usize {
112 self.b1_len
113 }
114 pub fn b2_len(&self) -> usize {
115 self.b2_len
116 }
117
118 pub fn get(&mut self, key: &K) -> Option<&V> {
122 let id = *self.index.get(key)?;
123 match self.nodes[id as usize].as_ref().unwrap().list {
124 List::T1 => {
125 self.unlink(id);
126 self.t1_len -= 1;
127 self.nodes[id as usize].as_mut().unwrap().list = List::T2;
128 self.push_front_t2(id);
129 self.t2_len += 1;
130 }
131 List::T2 => {
132 self.unlink(id);
133 self.t2_len -= 1;
134 self.push_front_t2(id);
135 self.t2_len += 1;
136 }
137 List::B1 | List::B2 => return None,
139 }
140 self.nodes[id as usize].as_ref().unwrap().value.as_ref()
141 }
142
143 pub fn put(&mut self, key: K, value: V) -> Option<(K, V)> {
145 if let Some(&id) = self.index.get(&key) {
146 match self.nodes[id as usize].as_ref().unwrap().list {
147 List::T1 => {
148 self.unlink(id);
150 self.t1_len -= 1;
151 let node = self.nodes[id as usize].as_mut().unwrap();
152 node.value = Some(value);
153 node.list = List::T2;
154 self.push_front_t2(id);
155 self.t2_len += 1;
156 return None;
157 }
158 List::T2 => {
159 self.unlink(id);
160 let node = self.nodes[id as usize].as_mut().unwrap();
161 node.value = Some(value);
162 self.push_front_t2(id);
163 return None;
164 }
165 List::B1 => {
166 let delta = (self.b2_len.max(1) / self.b1_len.max(1)).max(1);
168 self.p = (self.p + delta).min(self.c);
169 let evicted = self.replace(false);
170 self.unlink(id);
171 self.b1_len -= 1;
172 let node = self.nodes[id as usize].as_mut().unwrap();
173 node.value = Some(value);
174 node.list = List::T2;
175 self.push_front_t2(id);
176 self.t2_len += 1;
177 return evicted;
178 }
179 List::B2 => {
180 let delta = (self.b1_len.max(1) / self.b2_len.max(1)).max(1);
182 self.p = self.p.saturating_sub(delta);
183 let evicted = self.replace(true);
184 self.unlink(id);
185 self.b2_len -= 1;
186 let node = self.nodes[id as usize].as_mut().unwrap();
187 node.value = Some(value);
188 node.list = List::T2;
189 self.push_front_t2(id);
190 self.t2_len += 1;
191 return evicted;
192 }
193 }
194 }
195
196 let l1 = self.t1_len + self.b1_len;
198 let l2 = self.t2_len + self.b2_len;
199 let mut evicted = None;
200 if l1 == self.c {
201 if self.t1_len < self.c {
203 if let Some(victim) = self.pop_lru_b1() {
205 self.index.remove(&victim);
206 }
207 evicted = self.replace(false);
208 } else {
209 let id = self.t1_tail;
211 self.unlink(id);
212 self.t1_len -= 1;
213 let n = self.nodes[id as usize].take().unwrap();
214 self.index.remove(&n.key);
215 self.free.push(id);
216 evicted = Some((n.key, n.value.unwrap()));
217 }
218 } else if l1 + l2 >= self.c {
219 if l1 + l2 == 2 * self.c {
220 if let Some(victim) = self.pop_lru_b2() {
221 self.index.remove(&victim);
222 }
223 }
224 evicted = self.replace(false);
225 }
226
227 let id = self.alloc(Node {
228 key: key.clone(),
229 value: Some(value),
230 prev: NIL,
231 next: NIL,
232 list: List::T1,
233 });
234 self.index.insert(key, id);
235 self.push_front_t1(id);
236 self.t1_len += 1;
237 evicted
238 }
239
240 fn replace(&mut self, b2_hit: bool) -> Option<(K, V)> {
243 let force_t1 = b2_hit && self.t1_len == self.p;
244 if self.t1_len > 0 && (self.t1_len > self.p || force_t1) {
245 let id = self.t1_tail;
247 self.unlink(id);
248 self.t1_len -= 1;
249 let value = self.nodes[id as usize]
250 .as_mut()
251 .unwrap()
252 .value
253 .take()
254 .unwrap();
255 self.nodes[id as usize].as_mut().unwrap().list = List::B1;
256 self.push_front_b1(id);
257 self.b1_len += 1;
258 let key = self.nodes[id as usize].as_ref().unwrap().key.clone();
259 Some((key, value))
260 } else if self.t2_len > 0 {
261 let id = self.t2_tail;
262 self.unlink(id);
263 self.t2_len -= 1;
264 let value = self.nodes[id as usize]
265 .as_mut()
266 .unwrap()
267 .value
268 .take()
269 .unwrap();
270 self.nodes[id as usize].as_mut().unwrap().list = List::B2;
271 self.push_front_b2(id);
272 self.b2_len += 1;
273 let key = self.nodes[id as usize].as_ref().unwrap().key.clone();
274 Some((key, value))
275 } else {
276 None
277 }
278 }
279
280 fn alloc(&mut self, node: Node<K, V>) -> u32 {
281 if let Some(id) = self.free.pop() {
282 self.nodes[id as usize] = Some(node);
283 id
284 } else {
285 let id = self.nodes.len() as u32;
286 self.nodes.push(Some(node));
287 id
288 }
289 }
290
291 fn pop_lru_b1(&mut self) -> Option<K> {
292 if self.b1_tail == NIL {
293 return None;
294 }
295 let id = self.b1_tail;
296 self.unlink(id);
297 self.b1_len -= 1;
298 let n = self.nodes[id as usize].take().unwrap();
299 self.free.push(id);
300 Some(n.key)
301 }
302
303 fn pop_lru_b2(&mut self) -> Option<K> {
304 if self.b2_tail == NIL {
305 return None;
306 }
307 let id = self.b2_tail;
308 self.unlink(id);
309 self.b2_len -= 1;
310 let n = self.nodes[id as usize].take().unwrap();
311 self.free.push(id);
312 Some(n.key)
313 }
314
315 fn unlink(&mut self, id: u32) {
318 let (prev, next, list) = {
319 let n = self.nodes[id as usize].as_ref().unwrap();
320 (n.prev, n.next, n.list)
321 };
322 if prev != NIL {
323 self.nodes[prev as usize].as_mut().unwrap().next = next;
324 }
325 if next != NIL {
326 self.nodes[next as usize].as_mut().unwrap().prev = prev;
327 }
328 let n = self.nodes[id as usize].as_mut().unwrap();
329 n.prev = NIL;
330 n.next = NIL;
331 match list {
332 List::T1 => {
333 if self.t1_head == id {
334 self.t1_head = next;
335 }
336 if self.t1_tail == id {
337 self.t1_tail = prev;
338 }
339 }
340 List::T2 => {
341 if self.t2_head == id {
342 self.t2_head = next;
343 }
344 if self.t2_tail == id {
345 self.t2_tail = prev;
346 }
347 }
348 List::B1 => {
349 if self.b1_head == id {
350 self.b1_head = next;
351 }
352 if self.b1_tail == id {
353 self.b1_tail = prev;
354 }
355 }
356 List::B2 => {
357 if self.b2_head == id {
358 self.b2_head = next;
359 }
360 if self.b2_tail == id {
361 self.b2_tail = prev;
362 }
363 }
364 }
365 }
366
367 fn push_front_t1(&mut self, id: u32) {
368 let old_head = self.t1_head;
369 self.nodes[id as usize].as_mut().unwrap().next = old_head;
370 self.nodes[id as usize].as_mut().unwrap().prev = NIL;
371 if old_head != NIL {
372 self.nodes[old_head as usize].as_mut().unwrap().prev = id;
373 }
374 self.t1_head = id;
375 if self.t1_tail == NIL {
376 self.t1_tail = id;
377 }
378 }
379 fn push_front_t2(&mut self, id: u32) {
380 let old_head = self.t2_head;
381 self.nodes[id as usize].as_mut().unwrap().next = old_head;
382 self.nodes[id as usize].as_mut().unwrap().prev = NIL;
383 if old_head != NIL {
384 self.nodes[old_head as usize].as_mut().unwrap().prev = id;
385 }
386 self.t2_head = id;
387 if self.t2_tail == NIL {
388 self.t2_tail = id;
389 }
390 }
391 fn push_front_b1(&mut self, id: u32) {
392 let old_head = self.b1_head;
393 self.nodes[id as usize].as_mut().unwrap().next = old_head;
394 self.nodes[id as usize].as_mut().unwrap().prev = NIL;
395 if old_head != NIL {
396 self.nodes[old_head as usize].as_mut().unwrap().prev = id;
397 }
398 self.b1_head = id;
399 if self.b1_tail == NIL {
400 self.b1_tail = id;
401 }
402 }
403 fn push_front_b2(&mut self, id: u32) {
404 let old_head = self.b2_head;
405 self.nodes[id as usize].as_mut().unwrap().next = old_head;
406 self.nodes[id as usize].as_mut().unwrap().prev = NIL;
407 if old_head != NIL {
408 self.nodes[old_head as usize].as_mut().unwrap().prev = id;
409 }
410 self.b2_head = id;
411 if self.b2_tail == NIL {
412 self.b2_tail = id;
413 }
414 }
415}
416
417#[cfg(test)]
418#[path = "arc_tests.rs"]
419mod tests;