1use crate::pager::Pager;
2use rustc_hash::FxHashMap;
3
4struct LruEntry<Id, Page> {
19 page: Page,
20 prev: Option<Id>,
21 next: Option<Id>,
22}
23
24pub struct NodeCache<P>
25where
26 P: Pager,
27 P::Page: Clone,
28 P::Id: Clone + Eq + std::hash::Hash,
29{
30 map: FxHashMap<P::Id, LruEntry<P::Id, P::Page>>,
31 head: Option<P::Id>,
32 tail: Option<P::Id>,
33 cap: usize,
34}
35
36impl<P> Default for NodeCache<P>
37where
38 P: Pager,
39 P::Page: Clone,
40 P::Id: Clone + Eq + std::hash::Hash,
41{
42 fn default() -> Self {
43 NodeCache::<P>::new(1024, 2)
44 }
45}
46
47impl<P> NodeCache<P>
48where
49 P: Pager,
50 P::Page: Clone,
51 P::Id: Clone + Eq + std::hash::Hash,
52{
53 #[inline]
54 pub fn new(cap: usize, _unused: usize) -> Self {
55 let cap = cap.max(1);
57 Self {
58 map: FxHashMap::default(),
59 head: None,
60 tail: None,
61 cap,
62 }
63 }
64
65 #[inline]
67 pub fn peek(&self, id: &P::Id) -> Option<P::Page> {
68 self.map.get(id).map(|e| e.page.clone())
69 }
70
71 #[inline]
73 pub fn touch(&mut self, id: &P::Id) {
74 if self.map.contains_key(id) {
75 self.move_to_head(id);
76 }
77 }
78
79 #[inline]
80 pub fn set_limits(&mut self, read_cap: usize, _sweep_factor: usize) {
81 self.cap = read_cap.max(1);
82 while self.map.len() > self.cap {
83 self.evict_one();
84 }
85 }
86
87 #[inline]
88 pub fn get(&mut self, id: &P::Id) -> Option<P::Page> {
89 if !self.map.contains_key(id) {
90 return None;
91 }
92 self.move_to_head(id);
93 self.map.get(id).map(|e| e.page.clone())
94 }
95
96 #[inline]
97 pub fn insert(&mut self, id: P::Id, page: P::Page) {
98 if self.map.contains_key(&id) {
99 if let Some(e) = self.map.get_mut(&id) {
101 e.page = page;
102 }
103 self.move_to_head(&id);
104 return;
105 }
106 let old_head = self.head.clone();
108 let entry = LruEntry {
109 page,
110 prev: None,
111 next: old_head.clone(),
112 };
113 self.map.insert(id.clone(), entry);
114 if let Some(h) = old_head
115 && let Some(e) = self.map.get_mut(&h)
116 {
117 e.prev = Some(id.clone());
118 }
119 self.head = Some(id.clone());
120 if self.tail.is_none() {
121 self.tail = Some(id.clone());
122 }
123 if self.map.len() > self.cap {
124 self.evict_one();
125 }
126 }
127
128 #[inline]
129 pub fn invalidate(&mut self, id: &P::Id) {
130 if !self.map.contains_key(id) {
131 return;
132 }
133 let (prev, next) = {
134 let e = self.map.get(id).unwrap();
135 (e.prev.clone(), e.next.clone())
136 };
137 if let Some(p) = prev.clone()
139 && let Some(pe) = self.map.get_mut(&p)
140 {
141 pe.next = next.clone();
142 }
143 if let Some(n) = next.clone()
144 && let Some(ne) = self.map.get_mut(&n)
145 {
146 ne.prev = prev.clone();
147 }
148 if self.head.as_ref() == Some(id) {
150 self.head = next;
151 }
152 if self.tail.as_ref() == Some(id) {
153 self.tail = prev;
154 }
155 self.map.remove(id);
156 }
157
158 #[inline]
159 pub fn clear(&mut self) {
160 self.map.clear();
161 self.head = None;
162 self.tail = None;
163 }
164
165 #[inline]
166 fn move_to_head(&mut self, id: &P::Id) {
167 if self.head.as_ref() == Some(id) {
168 return;
169 }
170 let (prev, next) = {
171 let e = self.map.get(id).unwrap();
172 (e.prev.clone(), e.next.clone())
173 };
174 if let Some(p) = prev.clone()
176 && let Some(pe) = self.map.get_mut(&p)
177 {
178 pe.next = next.clone();
179 }
180 if let Some(n) = next.clone()
181 && let Some(ne) = self.map.get_mut(&n)
182 {
183 ne.prev = prev.clone();
184 }
185 if self.tail.as_ref() == Some(id) {
186 self.tail = prev.clone();
187 }
188 let old_head = self.head.clone();
190 if let Some(e) = self.map.get_mut(id) {
191 e.prev = None;
192 e.next = old_head.clone();
193 }
194 if let Some(h) = old_head
195 && let Some(he) = self.map.get_mut(&h)
196 {
197 he.prev = Some(id.clone());
198 }
199 self.head = Some(id.clone());
200 if self.tail.is_none() {
201 self.tail = Some(id.clone());
202 }
203 }
204
205 #[inline]
206 fn evict_one(&mut self) {
207 let Some(tid) = self.tail.clone() else {
208 return;
209 };
210 self.invalidate(&tid);
211 }
212}