Skip to main content

datafusion_execution/cache/
lru_queue.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::{
19    collections::HashMap,
20    hash::Hash,
21    sync::{Arc, Weak},
22};
23
24use parking_lot::Mutex;
25
26#[derive(Default)]
27/// Provides a Least Recently Used queue with unbounded capacity.
28///
29/// # Examples
30///
31/// ```
32/// use datafusion_execution::cache::lru_queue::LruQueue;
33///
34/// let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
35/// lru_queue.put(1, 10);
36/// lru_queue.put(2, 20);
37/// lru_queue.put(3, 30);
38/// assert_eq!(lru_queue.get(&2), Some(&20));
39/// assert_eq!(lru_queue.pop(), Some((1, 10)));
40/// assert_eq!(lru_queue.pop(), Some((3, 30)));
41/// assert_eq!(lru_queue.pop(), Some((2, 20)));
42/// assert_eq!(lru_queue.pop(), None);
43/// ```
44pub struct LruQueue<K: Eq + Hash + Clone, V> {
45    data: LruData<K, V>,
46    queue: LruList<K>,
47}
48
49/// Maps the key to the [`LruNode`] in queue and the value.
50type LruData<K, V> = HashMap<K, (Arc<Mutex<LruNode<K>>>, V)>;
51
52#[derive(Default)]
53/// Doubly-linked list that maintains the LRU order
54struct LruList<K> {
55    head: Link<K>,
56    tail: Link<K>,
57}
58
59/// Doubly-linked list node.
60struct LruNode<K> {
61    key: K,
62    prev: Link<K>,
63    next: Link<K>,
64}
65
66/// Weak pointer to a [`LruNode`], used to connect nodes in the doubly-linked list.
67/// The strong reference is guaranteed to be stored in the `data` map of the [`LruQueue`].
68type Link<K> = Option<Weak<Mutex<LruNode<K>>>>;
69
70impl<K: Eq + Hash + Clone, V> LruQueue<K, V> {
71    pub fn new() -> Self {
72        Self {
73            data: HashMap::new(),
74            queue: LruList {
75                head: None,
76                tail: None,
77            },
78        }
79    }
80
81    /// Returns a reference to value mapped by `key`, if it exists.
82    /// If the entry exists, it becomes the most recently used.
83    pub fn get(&mut self, key: &K) -> Option<&V> {
84        if let Some(value) = self.remove(key) {
85            self.put(key.clone(), value);
86        }
87        self.data.get(key).map(|(_, value)| value)
88    }
89
90    /// Returns a reference to value mapped by `key`, if it exists.
91    /// Does not affect the queue order.
92    pub fn peek(&self, key: &K) -> Option<&V> {
93        self.data.get(key).map(|(_, value)| value)
94    }
95
96    /// Checks whether there is an entry with key `key` in the queue.
97    /// Does not affect the queue order.
98    pub fn contains_key(&self, key: &K) -> bool {
99        self.data.contains_key(key)
100    }
101
102    /// Inserts an entry in the queue, becoming the most recently used.
103    /// If the entry already exists, returns the previous value.
104    pub fn put(&mut self, key: K, value: V) -> Option<V> {
105        let old_value = self.remove(&key);
106
107        let node = Arc::new(Mutex::new(LruNode {
108            key: key.clone(),
109            prev: None,
110            next: None,
111        }));
112
113        match self.queue.head {
114            // queue is not empty
115            Some(ref old_head) => {
116                old_head
117                    .upgrade()
118                    .expect("value has been unexpectedly dropped")
119                    .lock()
120                    .prev = Some(Arc::downgrade(&node));
121                node.lock().next = Some(Weak::clone(old_head));
122                self.queue.head = Some(Arc::downgrade(&node));
123            }
124            // queue is empty
125            _ => {
126                self.queue.head = Some(Arc::downgrade(&node));
127                self.queue.tail = Some(Arc::downgrade(&node));
128            }
129        }
130
131        self.data.insert(key, (node, value));
132
133        old_value
134    }
135
136    /// Removes and returns the least recently used value.
137    /// Returns `None` if the queue is empty.
138    pub fn pop(&mut self) -> Option<(K, V)> {
139        let key_to_remove = self.queue.tail.as_ref().map(|n| {
140            n.upgrade()
141                .expect("value has been unexpectedly dropped")
142                .lock()
143                .key
144                .clone()
145        });
146        if let Some(k) = key_to_remove {
147            let value = self.remove(&k).unwrap(); // confirmed above that the entry exists
148            Some((k, value))
149        } else {
150            None
151        }
152    }
153
154    /// Removes a specific entry from the queue, if it exists.
155    pub fn remove(&mut self, key: &K) -> Option<V> {
156        if let Some((old_node, old_value)) = self.data.remove(key) {
157            let LruNode { key: _, prev, next } = &*old_node.lock();
158            match (prev, next) {
159                // single node in the queue
160                (None, None) => {
161                    self.queue.head = None;
162                    self.queue.tail = None;
163                }
164                // removed the head node
165                (None, Some(n)) => {
166                    let n_strong =
167                        n.upgrade().expect("value has been unexpectedly dropped");
168                    n_strong.lock().prev = None;
169                    self.queue.head = Some(Weak::clone(n));
170                }
171                // removed the tail node
172                (Some(p), None) => {
173                    let p_strong =
174                        p.upgrade().expect("value has been unexpectedly dropped");
175                    p_strong.lock().next = None;
176                    self.queue.tail = Some(Weak::clone(p));
177                }
178                // removed a middle node
179                (Some(p), Some(n)) => {
180                    let n_strong =
181                        n.upgrade().expect("value has been unexpectedly dropped");
182                    let p_strong =
183                        p.upgrade().expect("value has been unexpectedly dropped");
184                    n_strong.lock().prev = Some(Weak::clone(p));
185                    p_strong.lock().next = Some(Weak::clone(n));
186                }
187            };
188            Some(old_value)
189        } else {
190            None
191        }
192    }
193
194    /// Returns the number of entries in the queue.
195    pub fn len(&self) -> usize {
196        self.data.len()
197    }
198
199    /// Checks whether the queue has no items.
200    pub fn is_empty(&self) -> bool {
201        self.data.is_empty()
202    }
203
204    /// Removes all entries from the queue.
205    pub fn clear(&mut self) {
206        self.queue.head = None;
207        self.queue.tail = None;
208        self.data.clear();
209    }
210
211    /// Returns a reference to the entries currently in the queue.
212    pub fn list_entries(&self) -> HashMap<&K, &V> {
213        self.data.iter().map(|(k, (_, v))| (k, v)).collect()
214    }
215
216    /// Returns an iterator over references to the keys currently in the queue.
217    /// The order is unspecified and does not reflect the LRU order.
218    pub fn keys(&self) -> impl Iterator<Item = &K> {
219        self.data.keys()
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use std::collections::HashMap;
226
227    use rand::seq::IndexedRandom;
228
229    use crate::cache::lru_queue::LruQueue;
230
231    #[test]
232    fn test_get() {
233        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
234
235        // value does not exist
236        assert_eq!(lru_queue.get(&1), None);
237
238        // value exists
239        lru_queue.put(1, 10);
240        assert_eq!(lru_queue.get(&1), Some(&10));
241        assert_eq!(lru_queue.get(&1), Some(&10));
242
243        // value is removed
244        lru_queue.remove(&1);
245        assert_eq!(lru_queue.get(&1), None);
246    }
247
248    #[test]
249    fn test_peek() {
250        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
251
252        // value does not exist
253        assert_eq!(lru_queue.peek(&1), None);
254
255        // value exists
256        lru_queue.put(1, 10);
257        assert_eq!(lru_queue.peek(&1), Some(&10));
258        assert_eq!(lru_queue.peek(&1), Some(&10));
259
260        // value is removed
261        lru_queue.remove(&1);
262        assert_eq!(lru_queue.peek(&1), None);
263    }
264
265    #[test]
266    fn test_put() {
267        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
268
269        // no previous value
270        assert_eq!(lru_queue.put(1, 10), None);
271
272        // update, the previous value is returned
273        assert_eq!(lru_queue.put(1, 11), Some(10));
274        assert_eq!(lru_queue.put(1, 12), Some(11));
275        assert_eq!(lru_queue.put(1, 13), Some(12));
276    }
277
278    #[test]
279    fn test_remove() {
280        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
281
282        // value does not exist
283        assert_eq!(lru_queue.remove(&1), None);
284
285        // value exists and is returned
286        lru_queue.put(1, 10);
287        assert_eq!(lru_queue.remove(&1), Some(10));
288
289        // value does not exist
290        assert_eq!(lru_queue.remove(&1), None);
291    }
292
293    #[test]
294    fn test_contains_key() {
295        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
296
297        // value does not exist
298        assert!(!lru_queue.contains_key(&1));
299
300        // value exists
301        lru_queue.put(1, 10);
302        assert!(lru_queue.contains_key(&1));
303
304        // value is removed
305        lru_queue.remove(&1);
306        assert!(!lru_queue.contains_key(&1));
307    }
308
309    #[test]
310    fn test_len() {
311        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
312
313        // empty
314        assert_eq!(lru_queue.len(), 0);
315
316        // puts
317        lru_queue.put(1, 10);
318        assert_eq!(lru_queue.len(), 1);
319        lru_queue.put(2, 20);
320        assert_eq!(lru_queue.len(), 2);
321        lru_queue.put(3, 30);
322        assert_eq!(lru_queue.len(), 3);
323        lru_queue.put(1, 11);
324        lru_queue.put(3, 31);
325        assert_eq!(lru_queue.len(), 3);
326
327        // removes
328        lru_queue.remove(&1);
329        assert_eq!(lru_queue.len(), 2);
330        lru_queue.remove(&1);
331        assert_eq!(lru_queue.len(), 2);
332        lru_queue.remove(&4);
333        assert_eq!(lru_queue.len(), 2);
334        lru_queue.remove(&3);
335        assert_eq!(lru_queue.len(), 1);
336        lru_queue.remove(&2);
337        assert_eq!(lru_queue.len(), 0);
338        lru_queue.remove(&2);
339        assert_eq!(lru_queue.len(), 0);
340
341        // clear
342        lru_queue.put(1, 10);
343        lru_queue.put(2, 20);
344        lru_queue.put(3, 30);
345        assert_eq!(lru_queue.len(), 3);
346        lru_queue.clear();
347        assert_eq!(lru_queue.len(), 0);
348    }
349
350    #[test]
351    fn test_is_empty() {
352        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
353
354        // empty
355        assert!(lru_queue.is_empty());
356
357        // puts
358        lru_queue.put(1, 10);
359        assert!(!lru_queue.is_empty());
360        lru_queue.put(2, 20);
361        assert!(!lru_queue.is_empty());
362
363        // removes
364        lru_queue.remove(&1);
365        assert!(!lru_queue.is_empty());
366        lru_queue.remove(&1);
367        assert!(!lru_queue.is_empty());
368        lru_queue.remove(&2);
369        assert!(lru_queue.is_empty());
370
371        // clear
372        lru_queue.put(1, 10);
373        lru_queue.put(2, 20);
374        lru_queue.put(3, 30);
375        assert!(!lru_queue.is_empty());
376        lru_queue.clear();
377        assert!(lru_queue.is_empty());
378    }
379
380    #[test]
381    fn test_clear() {
382        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
383
384        // empty
385        lru_queue.clear();
386
387        // filled
388        lru_queue.put(1, 10);
389        lru_queue.put(2, 20);
390        lru_queue.put(3, 30);
391        assert_eq!(lru_queue.get(&1), Some(&10));
392        assert_eq!(lru_queue.get(&2), Some(&20));
393        assert_eq!(lru_queue.get(&3), Some(&30));
394        lru_queue.clear();
395        assert_eq!(lru_queue.get(&1), None);
396        assert_eq!(lru_queue.get(&2), None);
397        assert_eq!(lru_queue.get(&3), None);
398        assert_eq!(lru_queue.len(), 0);
399    }
400
401    #[test]
402    fn test_pop() {
403        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
404
405        // empty queue
406        assert_eq!(lru_queue.pop(), None);
407
408        // simplest case
409        lru_queue.put(1, 10);
410        lru_queue.put(2, 20);
411        lru_queue.put(3, 30);
412        assert_eq!(lru_queue.pop(), Some((1, 10)));
413        assert_eq!(lru_queue.pop(), Some((2, 20)));
414        assert_eq!(lru_queue.pop(), Some((3, 30)));
415        assert_eq!(lru_queue.pop(), None);
416
417        // 'get' changes the order
418        lru_queue.put(1, 10);
419        lru_queue.put(2, 20);
420        lru_queue.put(3, 30);
421        lru_queue.get(&2);
422        assert_eq!(lru_queue.pop(), Some((1, 10)));
423        assert_eq!(lru_queue.pop(), Some((3, 30)));
424        assert_eq!(lru_queue.pop(), Some((2, 20)));
425        assert_eq!(lru_queue.pop(), None);
426
427        // multiple 'gets'
428        lru_queue.put(1, 10);
429        lru_queue.put(2, 20);
430        lru_queue.put(3, 30);
431        lru_queue.get(&2);
432        lru_queue.get(&3);
433        lru_queue.get(&1);
434        assert_eq!(lru_queue.pop(), Some((2, 20)));
435        assert_eq!(lru_queue.pop(), Some((3, 30)));
436        assert_eq!(lru_queue.pop(), Some((1, 10)));
437        assert_eq!(lru_queue.pop(), None);
438
439        // 'peak' does not change the order
440        lru_queue.put(1, 10);
441        lru_queue.put(2, 20);
442        lru_queue.put(3, 30);
443        lru_queue.peek(&2);
444        assert_eq!(lru_queue.pop(), Some((1, 10)));
445        assert_eq!(lru_queue.pop(), Some((2, 20)));
446        assert_eq!(lru_queue.pop(), Some((3, 30)));
447        assert_eq!(lru_queue.pop(), None);
448
449        // 'contains' does not change the order
450        lru_queue.put(1, 10);
451        lru_queue.put(2, 20);
452        lru_queue.put(3, 30);
453        lru_queue.contains_key(&2);
454        assert_eq!(lru_queue.pop(), Some((1, 10)));
455        assert_eq!(lru_queue.pop(), Some((2, 20)));
456        assert_eq!(lru_queue.pop(), Some((3, 30)));
457        assert_eq!(lru_queue.pop(), None);
458
459        // 'put' on the same key promotes it
460        lru_queue.put(1, 10);
461        lru_queue.put(2, 20);
462        lru_queue.put(3, 30);
463        lru_queue.put(2, 21);
464        assert_eq!(lru_queue.pop(), Some((1, 10)));
465        assert_eq!(lru_queue.pop(), Some((3, 30)));
466        assert_eq!(lru_queue.pop(), Some((2, 21)));
467        assert_eq!(lru_queue.pop(), None);
468
469        // multiple 'puts'
470        lru_queue.put(1, 10);
471        lru_queue.put(2, 20);
472        lru_queue.put(3, 30);
473        lru_queue.put(2, 21);
474        lru_queue.put(3, 31);
475        lru_queue.put(1, 11);
476        assert_eq!(lru_queue.pop(), Some((2, 21)));
477        assert_eq!(lru_queue.pop(), Some((3, 31)));
478        assert_eq!(lru_queue.pop(), Some((1, 11)));
479        assert_eq!(lru_queue.pop(), None);
480
481        // 'remove' an element in the middle of the queue
482        lru_queue.put(1, 10);
483        lru_queue.put(2, 20);
484        lru_queue.put(3, 30);
485        lru_queue.remove(&2);
486        assert_eq!(lru_queue.pop(), Some((1, 10)));
487        assert_eq!(lru_queue.pop(), Some((3, 30)));
488        assert_eq!(lru_queue.pop(), None);
489
490        // 'remove' the LRU
491        lru_queue.put(1, 10);
492        lru_queue.put(2, 20);
493        lru_queue.put(3, 30);
494        lru_queue.remove(&1);
495        assert_eq!(lru_queue.pop(), Some((2, 20)));
496        assert_eq!(lru_queue.pop(), Some((3, 30)));
497        assert_eq!(lru_queue.pop(), None);
498
499        // 'remove' the MRU
500        lru_queue.put(1, 10);
501        lru_queue.put(2, 20);
502        lru_queue.put(3, 30);
503        lru_queue.remove(&3);
504        assert_eq!(lru_queue.pop(), Some((1, 10)));
505        assert_eq!(lru_queue.pop(), Some((2, 20)));
506        assert_eq!(lru_queue.pop(), None);
507    }
508
509    #[test]
510    /// Fuzzy test using an hashmap as the base to check the methods.
511    fn test_fuzzy() {
512        let mut lru_queue: LruQueue<i32, i32> = LruQueue::new();
513        let mut map: HashMap<i32, i32> = HashMap::new();
514        let max_keys = 1_000;
515        let methods = ["get", "put", "remove", "pop", "contains", "len"];
516        let mut rng = rand::rng();
517
518        for i in 0..1_000_000 {
519            match *methods.choose(&mut rng).unwrap() {
520                "get" => {
521                    assert_eq!(lru_queue.get(&(i % max_keys)), map.get(&(i % max_keys)))
522                }
523                "put" => assert_eq!(
524                    lru_queue.put(i % max_keys, i),
525                    map.insert(i % max_keys, i)
526                ),
527                "remove" => assert_eq!(
528                    lru_queue.remove(&(i % max_keys)),
529                    map.remove(&(i % max_keys))
530                ),
531                "pop" => {
532                    let removed = lru_queue.pop();
533                    if let Some((k, v)) = removed {
534                        assert_eq!(Some(v), map.remove(&k))
535                    }
536                }
537                "contains" => {
538                    assert_eq!(
539                        lru_queue.contains_key(&(i % max_keys)),
540                        map.contains_key(&(i % max_keys))
541                    )
542                }
543                "len" => assert_eq!(lru_queue.len(), map.len()),
544                _ => unreachable!(),
545            }
546        }
547    }
548}