1use std::ptr;
2use std::sync::Mutex;
3
4use super::*;
5
6pub struct Lru {
7 shards: Vec<Mutex<Shard>>,
8}
9
10impl Lru {
11 pub fn new(cache_capacity: usize, cache_bits: usize) -> Lru {
13 assert!(
14 cache_bits <= 20,
15 "way too many shards. use a smaller number of cache_bits"
16 );
17 let size = 1 << cache_bits;
18 let shard_capacity = cache_capacity / size;
19
20 Lru {
21 shards: rep_no_copy![Mutex::new(Shard::new(shard_capacity)); size],
22 }
23 }
24
25 pub fn accessed(&self, pid: PageID, sz: usize) -> Vec<PageID> {
29 let shard_idx = pid % self.shards.len();
30 let rel_idx = pid / self.shards.len();
31 let shard_mu = &self.shards[shard_idx];
32 let mut shard = shard_mu.lock().unwrap();
33 let mut rel_ids = shard.accessed(rel_idx, sz);
34
35 for rel_id in &mut rel_ids {
36 let real_id = (*rel_id * self.shards.len()) + shard_idx;
37 *rel_id = real_id;
38 }
39
40 rel_ids
41 }
42}
43
44#[derive(Clone)]
45struct Entry {
46 ptr: *mut dll::Node,
47 sz: usize,
48}
49
50impl Default for Entry {
51 fn default() -> Entry {
52 Entry {
53 ptr: ptr::null_mut(),
54 sz: 0,
55 }
56 }
57}
58
59struct Shard {
60 list: Dll,
61 entries: Vec<Entry>,
62 capacity: usize,
63 sz: usize,
64}
65
66impl Shard {
67 fn new(capacity: usize) -> Shard {
68 Shard {
69 list: Dll::default(),
70 entries: vec![],
71 capacity: capacity,
72 sz: 0,
73 }
74 }
75
76 fn accessed(&mut self, rel_idx: PageID, sz: usize) -> Vec<PageID> {
77 if self.entries.len() <= rel_idx {
78 self.entries.resize(rel_idx + 1, Entry::default());
79 }
80
81 {
82 let entry = &mut self.entries[rel_idx];
83
84 self.sz -= entry.sz;
85 entry.sz = sz;
86 self.sz += sz;
87
88 if entry.ptr.is_null() {
89 entry.ptr = self.list.push_head(rel_idx);
90 } else {
91 entry.ptr = self.list.promote(entry.ptr);
92 }
93 }
94
95 let mut to_evict = vec![];
96 while self.sz > self.capacity {
97 if self.list.len() == 1 {
98 break;
100 }
101
102 let min_pid = self.list.pop_tail().unwrap();
103 self.entries[min_pid].ptr = ptr::null_mut();
104
105 to_evict.push(min_pid);
106
107 self.sz -= self.entries[min_pid].sz;
108 self.entries[min_pid].sz = 0;
109 }
110
111 to_evict
112 }
113}