1use std::{
16 mem::offset_of,
17 sync::{
18 Arc,
19 atomic::{AtomicBool, Ordering},
20 },
21};
22
23use foyer_common::{
24 code::{Key, Value},
25 error::Result,
26 properties::Properties,
27};
28use intrusive_collections::{LinkedList, LinkedListAtomicLink, intrusive_adapter};
29use serde::{Deserialize, Serialize};
30
31use super::{Eviction, Op};
32use crate::record::Record;
33
34#[derive(Debug, Clone, Default, Serialize, Deserialize)]
36pub struct SieveConfig;
37
38#[derive(Debug, Default)]
39pub struct SieveState {
40 link: LinkedListAtomicLink,
41 visited: AtomicBool,
42}
43
44impl SieveState {
45 #[inline]
46 fn is_visited(&self) -> bool {
47 self.visited.load(Ordering::Relaxed)
48 }
49
50 fn set_visited(&self, visited: bool) {
51 self.visited.store(visited, Ordering::Relaxed);
52 }
53}
54
55intrusive_adapter! {
56 Adapter<K, V, P> = Arc<Record<Sieve<K, V, P>>>: Record<Sieve<K, V, P>> {
57 ?offset = Record::<Sieve<K, V, P>>::STATE_OFFSET + offset_of!(SieveState, link) => LinkedListAtomicLink
58 }
59 where K: Key, V: Value, P: Properties
60}
61
62pub struct Sieve<K, V, P>
76where
77 K: Key,
78 V: Value,
79 P: Properties,
80{
81 queue: LinkedList<Adapter<K, V, P>>,
82 hand: Option<Arc<Record<Sieve<K, V, P>>>>,
84}
85
86impl<K, V, P> Eviction for Sieve<K, V, P>
87where
88 K: Key,
89 V: Value,
90 P: Properties,
91{
92 type Config = SieveConfig;
93 type Key = K;
94 type Value = V;
95 type Properties = P;
96 type State = SieveState;
97
98 fn new(_capacity: usize, _config: &Self::Config) -> Self
99 where
100 Self: Sized,
101 {
102 Self {
103 queue: LinkedList::new(Adapter::new()),
104 hand: None,
105 }
106 }
107
108 fn update(&mut self, _: usize, _: Option<&Self::Config>) -> Result<()> {
109 Ok(())
110 }
111
112 fn push(&mut self, record: Arc<Record<Self>>) {
113 record.set_in_eviction(true);
114 self.queue.push_back(record);
115 }
116
117 fn pop(&mut self) -> Option<Arc<Record<Self>>> {
118 let mut candidate = if let Some(ref hand_ptr) = self.hand {
119 unsafe { self.queue.cursor_mut_from_ptr(Arc::as_ptr(hand_ptr)) }
120 } else {
121 self.queue.front_mut()
122 };
123
124 loop {
125 {
126 let record = candidate.get()?;
127 let state = unsafe { &*record.state().get() };
128 if !state.is_visited() {
129 break;
130 } else {
131 state.set_visited(false);
132 if candidate.peek_next().is_null() {
133 candidate = self.queue.front_mut();
134 } else {
135 candidate.move_next();
136 }
137 }
138 }
139 }
140
141 self.hand = candidate.peek_next().clone_pointer();
142 candidate.remove().inspect(|record| record.set_in_eviction(false))
143 }
144
145 fn remove(&mut self, record: &Arc<Record<Self>>) {
146 if let Some(ref hand_ptr) = self.hand
147 && Arc::ptr_eq(hand_ptr, record)
148 {
149 self.hand = None;
151 }
152
153 unsafe { self.queue.remove_from_ptr(Arc::as_ptr(record)) };
154 record.set_in_eviction(false);
155 }
156
157 fn acquire() -> Op<Self> {
158 Op::immutable(|_: &Self, record| {
159 let state = unsafe { &*record.state().get() };
160 state.set_visited(true);
161 })
162 }
163
164 fn release() -> Op<Self> {
165 Op::noop()
166 }
167}
168
169#[cfg(test)]
170pub mod tests {
171 use itertools::Itertools;
172
173 use super::*;
174 use crate::{
175 eviction::test_utils::{Dump, OpExt, TestProperties, assert_ptr_eq, assert_ptr_vec_eq},
176 record::Data,
177 };
178
179 impl<K, V> Dump for Sieve<K, V, TestProperties>
180 where
181 K: Key + Clone,
182 V: Value + Clone,
183 {
184 type Output = Vec<Arc<Record<Self>>>;
185 fn dump(&self) -> Self::Output {
186 let mut res = vec![];
187 let mut cursor = self.queue.cursor();
188 loop {
189 cursor.move_next();
190 match cursor.clone_pointer() {
191 Some(record) => res.push(record),
192 None => break,
193 }
194 }
195 res
196 }
197 }
198
199 type TestSieve = Sieve<u64, u64, TestProperties>;
200
201 #[test]
202 fn test_sieve_basic() {
203 let rs = (0..8)
204 .map(|i| {
205 Arc::new(Record::new(Data {
206 key: i,
207 value: i,
208 properties: TestProperties::default(),
209 hash: i,
210 weight: 1,
211 }))
212 })
213 .collect_vec();
214 let r = |i: usize| rs[i].clone();
215 let mut sieve = TestSieve::new(100, &SieveConfig {});
216
217 sieve.push(r(0));
219 sieve.push(r(1));
220 sieve.push(r(2));
221 sieve.push(r(3));
222 assert_ptr_vec_eq(sieve.dump(), vec![r(0), r(1), r(2), r(3)]);
223
224 sieve.acquire_immutable(&r(1));
225 sieve.acquire_immutable(&r(3));
226
227 let r0 = sieve.pop().unwrap();
229 assert_ptr_eq(&rs[0], &r0);
230
231 let r2 = sieve.pop().unwrap();
233 assert_ptr_eq(&rs[2], &r2);
234
235 assert_ptr_vec_eq(sieve.dump(), vec![r(1), r(3)]);
238
239 let r1 = sieve.pop().unwrap();
241 assert_ptr_eq(&rs[1], &r1);
242
243 assert_ptr_vec_eq(sieve.dump(), vec![r(3)]);
244
245 sieve.remove(&r(3));
246 assert_ptr_vec_eq(sieve.dump(), vec![]);
247
248 sieve.push(r(4));
250 sieve.push(r(5));
251 sieve.push(r(6));
252 sieve.clear();
253 assert_ptr_vec_eq(sieve.dump(), vec![]);
254 }
255}