caches/lru/two_queue.rs
1use crate::lru::raw::EntryNode;
2use crate::lru::{
3 swap_value, CacheError, DefaultEvictCallback, KeysLRUIter, KeysMRUIter, LRUIter, LRUIterMut,
4 MRUIter, MRUIterMut, RawLRU, ValuesLRUIter, ValuesLRUIterMut, ValuesMRUIter, ValuesMRUIterMut,
5};
6use crate::{Cache, DefaultHashBuilder, KeyRef, PutResult};
7use alloc::boxed::Box;
8use alloc::fmt;
9use core::borrow::Borrow;
10use core::hash::{BuildHasher, Hash};
11
12// f64 function polyfill to support no_std contexts
13use crate::polyfill::floor;
14
15/// `DEFAULT_2Q_RECENT_RATIO` is the ratio of the [`TwoQueueCache`] dedicated
16/// to recently added entries that have only been accessed once.
17///
18/// [`TwoQueueCache`]: struct.TwoQueueCache.html
19pub const DEFAULT_2Q_RECENT_RATIO: f64 = 0.25;
20
21/// `DEFAULT_2Q_GHOST_ENTRIES` is the default ratio of ghost
22/// entries kept to track entries recently evicted for [`TwoQueueCache`].
23///
24/// [`TwoQueueCache`]: struct.TwoQueueCache.html
25pub const DEFAULT_2Q_GHOST_RATIO: f64 = 0.5;
26
27/// `TwoQueueCacheBuilder` is used to help build a [`TwoQueueCache`] with custom configuration.
28///
29/// [`TwoQueueCache`]: struct.TwoQueueCache.html
30pub struct TwoQueueCacheBuilder<
31 RH = DefaultHashBuilder,
32 FH = DefaultHashBuilder,
33 GH = DefaultHashBuilder,
34> {
35 size: usize,
36 ghost_ratio: Option<f64>,
37 recent_ratio: Option<f64>,
38 recent_hasher: Option<RH>,
39 freq_hasher: Option<FH>,
40 ghost_hasher: Option<GH>,
41}
42
43impl Default for TwoQueueCacheBuilder {
44 /// Create a default `TwoQueueCacheBuilder`.
45 ///
46 /// # Example
47 /// ```rust
48 /// use caches::{TwoQueueCacheBuilder, TwoQueueCache, Cache};
49 /// let mut cache: TwoQueueCache<u64, u64> = TwoQueueCacheBuilder::default()
50 /// .set_size(5)
51 /// .finalize()
52 /// .unwrap();
53 ///
54 /// cache.put(1, 1);
55 /// ```
56 fn default() -> Self {
57 Self {
58 size: 0,
59 ghost_ratio: Some(DEFAULT_2Q_GHOST_RATIO),
60 recent_ratio: Some(DEFAULT_2Q_RECENT_RATIO),
61 recent_hasher: Some(DefaultHashBuilder::default()),
62 freq_hasher: Some(DefaultHashBuilder::default()),
63 ghost_hasher: Some(DefaultHashBuilder::default()),
64 }
65 }
66}
67
68impl TwoQueueCacheBuilder {
69 /// Returns a default [`TwoQueueCacheBuilder`].
70 ///
71 /// # Example
72 /// ```rust
73 /// use caches::{TwoQueueCacheBuilder, TwoQueueCache, Cache};
74 /// use rustc_hash::FxHasher;
75 /// use std::hash::BuildHasherDefault;
76 ///
77 /// let mut cache = TwoQueueCacheBuilder::new(3)
78 /// .set_recent_ratio(0.3)
79 /// .set_ghost_ratio(0.4)
80 /// .set_recent_hasher(BuildHasherDefault::<FxHasher>::default())
81 /// .set_frequent_hasher(BuildHasherDefault::<FxHasher>::default())
82 /// .set_ghost_hasher(BuildHasherDefault::<FxHasher>::default())
83 /// .finalize::<u64, u64>()
84 /// .unwrap();
85 ///
86 /// cache.put(1, 1);
87 /// ```
88 ///
89 /// [`TwoQueueCacheBuilder`]: struct.TwoQueueCacheBuilder.html
90 pub fn new(size: usize) -> Self {
91 Self::default().set_size(size)
92 }
93}
94
95impl<RH: BuildHasher, FH: BuildHasher, GH: BuildHasher> TwoQueueCacheBuilder<RH, FH, GH> {
96 /// Set the ghost LRU size ratio
97 pub fn set_ghost_ratio(self, ratio: f64) -> Self {
98 TwoQueueCacheBuilder {
99 size: self.size,
100 ghost_ratio: Some(ratio),
101 recent_ratio: self.recent_ratio,
102 recent_hasher: self.recent_hasher,
103 freq_hasher: self.freq_hasher,
104 ghost_hasher: self.ghost_hasher,
105 }
106 }
107
108 /// Set the recent LRU size ratio
109 pub fn set_recent_ratio(self, ratio: f64) -> Self {
110 TwoQueueCacheBuilder {
111 size: self.size,
112 ghost_ratio: self.ghost_ratio,
113 recent_ratio: Some(ratio),
114 recent_hasher: self.recent_hasher,
115 freq_hasher: self.freq_hasher,
116 ghost_hasher: self.ghost_hasher,
117 }
118 }
119
120 /// Set the cache size
121 pub fn set_size(self, size: usize) -> Self {
122 TwoQueueCacheBuilder {
123 size,
124 ghost_ratio: self.ghost_ratio,
125 recent_ratio: self.recent_ratio,
126 recent_hasher: self.recent_hasher,
127 freq_hasher: self.freq_hasher,
128 ghost_hasher: self.ghost_hasher,
129 }
130 }
131
132 /// Set the recent LRU's hash builder
133 pub fn set_recent_hasher<NRH: BuildHasher>(
134 self,
135 hasher: NRH,
136 ) -> TwoQueueCacheBuilder<NRH, FH, GH> {
137 TwoQueueCacheBuilder {
138 size: self.size,
139 ghost_ratio: self.ghost_ratio,
140 recent_ratio: self.recent_ratio,
141 recent_hasher: Some(hasher),
142 freq_hasher: self.freq_hasher,
143 ghost_hasher: self.ghost_hasher,
144 }
145 }
146
147 /// Set the frequent LRU's hash builder
148 pub fn set_frequent_hasher<NFH: BuildHasher>(
149 self,
150 hasher: NFH,
151 ) -> TwoQueueCacheBuilder<RH, NFH, GH> {
152 TwoQueueCacheBuilder {
153 size: self.size,
154 ghost_ratio: self.ghost_ratio,
155 recent_ratio: self.recent_ratio,
156 recent_hasher: self.recent_hasher,
157 freq_hasher: Some(hasher),
158 ghost_hasher: self.ghost_hasher,
159 }
160 }
161
162 /// Set the ghost LRU's hash builder
163 pub fn set_ghost_hasher<NGH: BuildHasher>(
164 self,
165 hasher: NGH,
166 ) -> TwoQueueCacheBuilder<RH, FH, NGH> {
167 TwoQueueCacheBuilder {
168 size: self.size,
169 ghost_ratio: self.ghost_ratio,
170 recent_ratio: self.recent_ratio,
171 recent_hasher: self.recent_hasher,
172 freq_hasher: self.freq_hasher,
173 ghost_hasher: Some(hasher),
174 }
175 }
176
177 /// Finalize the builder to [`TwoQueueCache`]
178 ///
179 /// [`TwoQueueCache`]: struct.TwoQueueCache.html
180 pub fn finalize<K: Hash + Eq, V>(self) -> Result<TwoQueueCache<K, V, RH, FH, GH>, CacheError> {
181 let size = self.size;
182 if size == 0 {
183 return Err(CacheError::InvalidSize(0));
184 }
185
186 let rr = self.recent_ratio.unwrap();
187 if !(0.0..=1.0).contains(&rr) {
188 return Err(CacheError::InvalidRecentRatio(rr));
189 }
190
191 let gr = self.ghost_ratio.unwrap();
192 if !(0.0..=1.0).contains(&gr) {
193 return Err(CacheError::InvalidGhostRatio(gr));
194 }
195
196 // Determine the sub-sizes
197 let rs = floor((size as f64) * rr) as usize;
198 let es = floor((size as f64) * gr) as usize;
199
200 // allocate the lrus
201
202 let recent = RawLRU::with_hasher(size, self.recent_hasher.unwrap()).unwrap();
203 let freq = RawLRU::with_hasher(size, self.freq_hasher.unwrap()).unwrap();
204
205 let ghost = RawLRU::with_hasher(es, self.ghost_hasher.unwrap()).unwrap();
206
207 Ok(TwoQueueCache {
208 size,
209 recent_size: rs,
210 recent,
211 frequent: freq,
212 ghost,
213 })
214 }
215}
216
217/// `TwoQueueCache` is a fixed size 2Q cache.
218/// 2Q is an enhancement over the standard LRU cache
219/// in that it tracks both frequently and recently used
220/// entries separately. This avoids a burst in access to new
221/// entries from evicting frequently used entries. It adds some
222/// additional tracking overhead to the [`RawLRU`] cache, and is
223/// computationally about **2x** the cost, and adds some metadata over
224/// head. The [`AdaptiveCache`] is similar to the TwoQueueCache, but does not require setting any
225/// parameters.
226///
227/// # Example
228///
229/// ```rust
230///
231/// use caches::{TwoQueueCache, Cache, PutResult};
232///
233/// let mut cache = TwoQueueCache::new(4).unwrap();
234///
235/// // Add 1,2,3,4,
236/// (1..=4).for_each(|i| {
237/// assert_eq!(cache.put(i, i), PutResult::Put);
238/// });
239///
240/// // Add 5 -> Evict 1 to ghost LRU
241/// assert_eq!(cache.put(5, 5), PutResult::Put);
242///
243/// // Pull in the recently evicted
244/// assert_eq!(cache.put(1, 1), PutResult::Update(1));
245///
246/// // Add 6, should cause another recent evict
247/// assert_eq!(cache.put(6, 6), PutResult::<i32, i32>::Put);
248///
249/// // Add 7, should evict an entry from ghost LRU.
250/// assert_eq!(cache.put(7, 7), PutResult::Evicted { key: 2, value: 2 });
251///
252/// // Add 2, should evict an entry from ghost LRU
253/// assert_eq!(cache.put(2, 11), PutResult::Evicted { key: 3, value: 3 });
254///
255/// // Add 4, should put the entry from ghost LRU to freq LRU
256/// assert_eq!(cache.put(4, 11), PutResult::Update(4));
257///
258/// // move all entry in recent to freq.
259/// assert_eq!(cache.put(2, 22), PutResult::Update(11));
260/// assert_eq!(cache.put(7, 77), PutResult::<i32, i32>::Update(7));
261///
262/// // Add 6, should put the entry from ghost LRU to freq LRU, and evicted one
263/// // entry
264/// assert_eq!(cache.put(6, 66), PutResult::EvictedAndUpdate { evicted: (5, 5), update: 6});
265/// assert_eq!(cache.recent_len(), 0);
266/// assert_eq!(cache.ghost_len(), 1);
267/// assert_eq!(cache.frequent_len(), 4);
268/// ```
269///
270/// [`RawLRU`]: struct.RawLRU.html
271/// [`AdaptiveCache`]: struct.AdaptiveCache.html
272pub struct TwoQueueCache<
273 K: Hash + Eq,
274 V,
275 RH = DefaultHashBuilder,
276 FH = DefaultHashBuilder,
277 GH = DefaultHashBuilder,
278> {
279 size: usize,
280 recent_size: usize,
281 recent: RawLRU<K, V, DefaultEvictCallback, RH>,
282 frequent: RawLRU<K, V, DefaultEvictCallback, FH>,
283 ghost: RawLRU<K, V, DefaultEvictCallback, GH>,
284}
285
286impl<K: Hash + Eq, V> TwoQueueCache<K, V> {
287 /// Create a `TwoQueueCache` with size and default configurations.
288 pub fn new(size: usize) -> Result<Self, CacheError> {
289 Self::with_2q_parameters(size, DEFAULT_2Q_RECENT_RATIO, DEFAULT_2Q_GHOST_RATIO)
290 }
291
292 /// Returns a [`TwoQueueCacheBuilder`] to help build a [`TwoQueueCache`].
293 ///
294 /// # Example
295 /// ```rust
296 /// use caches::{TwoQueueCacheBuilder, TwoQueueCache, Cache};
297 /// use rustc_hash::FxHasher;
298 /// use std::hash::BuildHasherDefault;
299 ///
300 /// let mut cache = TwoQueueCache::<u64, u64>::builder(3)
301 /// .set_recent_ratio(0.3)
302 /// .set_ghost_ratio(0.4)
303 /// .set_recent_hasher(BuildHasherDefault::<FxHasher>::default())
304 /// .set_frequent_hasher(BuildHasherDefault::<FxHasher>::default())
305 /// .set_ghost_hasher(BuildHasherDefault::<FxHasher>::default())
306 /// .finalize::<u64, u64>()
307 /// .unwrap();
308 ///
309 /// cache.put(1, 1);
310 /// ```
311 ///
312 /// [`TwoQueueCacheBuilder`]: struct.TwoQueueCacheBuilder.html
313 /// [`TwoQueueCache`]: struct.TwoQueueCache.html
314 pub fn builder(size: usize) -> TwoQueueCacheBuilder {
315 TwoQueueCacheBuilder::new(size)
316 }
317
318 /// Create a cache with size and recent ratio.
319 ///
320 /// # Example
321 ///
322 /// ```rust
323 /// use caches::{Cache, TwoQueueCache};
324 ///
325 /// let mut cache: TwoQueueCache<u64, u64>= TwoQueueCache::with_recent_ratio(5, 0.3).unwrap();
326 /// ```
327 pub fn with_recent_ratio(size: usize, rr: f64) -> Result<Self, CacheError> {
328 Self::with_2q_parameters(size, rr, DEFAULT_2Q_GHOST_RATIO)
329 }
330
331 /// Create a cache with size and ghost ratio.
332 ///
333 /// # Example
334 ///
335 /// ```rust
336 /// use caches::{Cache, TwoQueueCache};
337 ///
338 /// let mut cache: TwoQueueCache<u64, u64>= TwoQueueCache::with_ghost_ratio(5, 0.6).unwrap();
339 /// ```
340 pub fn with_ghost_ratio(size: usize, gr: f64) -> Result<Self, CacheError> {
341 Self::with_2q_parameters(size, DEFAULT_2Q_RECENT_RATIO, gr)
342 }
343
344 /// Create a cache with size, recent ratio and ghost ratio
345 ///
346 /// # Example
347 ///
348 /// ```rust
349 /// use caches::{Cache, TwoQueueCache};
350 ///
351 /// let mut cache: TwoQueueCache<u64, u64>= TwoQueueCache::with_2q_parameters(5, 0.3, 0.6).unwrap();
352 /// ```
353 pub fn with_2q_parameters(size: usize, rr: f64, gr: f64) -> Result<Self, CacheError> {
354 if size == 0 {
355 return Err(CacheError::InvalidSize(size));
356 }
357
358 if !(0.0..=1.0).contains(&rr) {
359 return Err(CacheError::InvalidRecentRatio(rr));
360 }
361
362 if !(0.0..=1.0).contains(&gr) {
363 return Err(CacheError::InvalidGhostRatio(gr));
364 }
365
366 // Determine the sub-sizes
367 let rs = floor((size as f64) * rr) as usize;
368 let es = floor((size as f64) * gr) as usize;
369
370 // allocate the lrus
371 let recent = RawLRU::new(size).unwrap();
372 let freq = RawLRU::new(size).unwrap();
373
374 let ghost = RawLRU::new(es)?;
375
376 Ok(Self {
377 size,
378 recent_size: rs,
379 recent,
380 frequent: freq,
381 ghost,
382 })
383 }
384}
385
386impl<K: Hash + Eq, V, RH: BuildHasher, FH: BuildHasher, GH: BuildHasher> Cache<K, V>
387 for TwoQueueCache<K, V, RH, FH, GH>
388{
389 /// Puts a key-value pair to the cache.
390 ///
391 /// # Note
392 /// - [`TwoQueueCache`] guarantees that the size of the recent LRU plus the size of the freq LRU
393 /// is less or equal to the [`TwoQueueCache`]'s size.
394 /// - The ghost LRU has its own size.
395 ///
396 /// # Example
397 /// ```rust
398 /// use caches::{TwoQueueCache, Cache, PutResult};
399 ///
400 /// let mut cache = TwoQueueCache::new(4).unwrap();
401 /// // Add 1,2,3,4,5 -> Evict 1
402 /// cache.put(1, 1);
403 /// cache.put(2, 2);
404 /// cache.put(3, 3);
405 /// cache.put(4, 4);
406 /// cache.put(5, 5);
407 ///
408 /// // Pull in the recently evicted
409 /// assert_eq!(cache.put(1, 1), PutResult::Update(1));
410 ///
411 /// // Add 6, should cause another recent evict
412 /// assert_eq!(cache.put(6, 6), PutResult::Put);
413 ///
414 /// // Add 7, should evict an entry from ghost LRU.
415 /// assert_eq!(cache.put(7, 7), PutResult::Evicted { key: 2, value: 2});
416 ///
417 /// // Add 2, should evict an entry from ghost LRU
418 /// assert_eq!(cache.put(2, 11), PutResult::Evicted { key: 3, value: 3});
419 ///
420 /// // Add 4, should put the entry from ghost LRU to freq LRU
421 /// assert_eq!(cache.put(4, 11), PutResult::Update(4));
422 ///
423 /// // move all entry in recent to freq.
424 /// assert_eq!(cache.put(2, 22), PutResult::Update(11));
425 /// assert_eq!(cache.put(7, 77), PutResult::Update(7));
426 ///
427 /// // Add 6, should put the entry from ghost LRU to freq LRU, and evicted one
428 /// // entry
429 /// assert_eq!(cache.put(6, 66), PutResult::EvictedAndUpdate { evicted: (5, 5), update: 6 });
430 /// ```
431 ///
432 /// [`TwoQueueCache`]: struct.TwoQueueCache.html
433 fn put(&mut self, k: K, mut v: V) -> PutResult<K, V> {
434 let key_ref = KeyRef { k: &k };
435
436 // Check if the value is frequently used already,
437 // and just update the value
438 if let Some(ent_ptr) = self.frequent.map.get_mut(&key_ref).map(|node| {
439 let node_ptr: *mut EntryNode<K, V> = node.as_ptr();
440 node_ptr
441 }) {
442 self.frequent.update(&mut v, ent_ptr);
443 return PutResult::Update(v);
444 }
445
446 // Check if the value is recently used, and promote
447 // the value into the frequent list
448 if self
449 .recent
450 // here we remove an entry from recent LRU if key exists
451 .remove_and_return_ent(&k)
452 .map(|mut ent| {
453 unsafe {
454 swap_value(&mut v, ent.as_mut());
455 }
456 // here we add the entry to frequent LRU,
457 // the result will always be PutResult::Put
458 // because we have removed this entry from recent LRU
459 self.frequent.put_nonnull(ent)
460 })
461 .is_some()
462 {
463 return PutResult::Update(v);
464 }
465
466 // if we have space, nothing to do
467 let recent_len = self.recent.len();
468 let freq_len = self.frequent.len();
469
470 // If the value was recently evicted, add it to the
471 // frequently used list
472 if self.ghost.contains(&k) {
473 return if recent_len + freq_len >= self.size {
474 let ent = if recent_len > self.recent_size {
475 self.recent.remove_lru_in().unwrap()
476 } else {
477 self.frequent.remove_lru_in().unwrap()
478 };
479
480 let rst = self.ghost.put_or_evict_nonnull(ent);
481 match self.ghost.map.remove(&key_ref) {
482 None => match rst {
483 None => PutResult::Put,
484 Some(mut ent) => {
485 unsafe {
486 let ent_ptr = ent.as_mut();
487 core::ptr::swap(&mut v, ent_ptr.val.as_mut_ptr());
488 }
489 self.frequent.put_nonnull(ent);
490 PutResult::Update(v)
491 }
492 },
493 Some(mut ent) => {
494 let ent_ptr = ent.as_ptr();
495 self.ghost.detach(ent_ptr);
496
497 unsafe {
498 let ent_ref = ent.as_mut();
499 core::ptr::swap(&mut v, ent_ref.val.as_mut_ptr());
500 self.frequent.put_nonnull(ent);
501 match rst {
502 None => PutResult::Update(v),
503 Some(ent) => {
504 let ptr = ent.as_ptr();
505 let ent = *Box::from_raw(ptr);
506 PutResult::EvictedAndUpdate {
507 evicted: (ent.key.assume_init(), ent.val.assume_init()),
508 update: v,
509 }
510 }
511 }
512 }
513 }
514 }
515 } else {
516 let mut ent = self.ghost.map.remove(&key_ref).unwrap();
517 let ent_ptr = ent.as_ptr();
518 self.ghost.detach(ent_ptr);
519 unsafe {
520 core::ptr::swap(&mut v, ent.as_mut().val.as_mut_ptr());
521 }
522 self.frequent.put_nonnull(ent);
523 PutResult::Update(v)
524 };
525 }
526
527 // Add to the recently seen list.
528 let bks = unsafe {
529 core::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(EntryNode::new(k, v))))
530 };
531 // if we have enough space, we add entry to recent LRU directly
532 if freq_len + recent_len < self.size {
533 return match self.recent.put_or_evict_nonnull(bks) {
534 None => PutResult::Put,
535 Some(evicted) => self.ghost.put_nonnull(evicted),
536 };
537 }
538
539 // The cache does not have enough space, so we remove one entry from freq LRU or recent
540 // LRU. Then, put the removed entry to the front of the ghost LRU,
541 // if ghost LRU is also full, the cache will evict the less recent used entry of
542 // ghost LRU.
543 let ent = if recent_len >= self.recent_size {
544 self.recent.remove_lru_in().unwrap()
545 } else {
546 self.frequent.remove_lru_in().unwrap()
547 };
548
549 self.recent.put_nonnull(bks);
550 self.ghost.put_nonnull(ent)
551 }
552
553 /// Returns a mutable reference to the value of the key in the cache or `None` if it
554 /// is not present in the cache. Moves the key to the head of the LRU list if it exists.
555 ///
556 /// # Example
557 ///
558 /// ```
559 /// use caches::{Cache, TwoQueueCache};
560 /// let mut cache = TwoQueueCache::new(2).unwrap();
561 ///
562 /// cache.put("apple", 8);
563 /// cache.put("banana", 4);
564 /// cache.put("banana", 6);
565 /// cache.put("pear", 2);
566 ///
567 /// assert_eq!(cache.get(&"banana"), Some(&6));
568 /// ```
569 fn get<Q>(&mut self, k: &Q) -> Option<&V>
570 where
571 K: Borrow<Q>,
572 Q: Hash + Eq + ?Sized,
573 {
574 // Check if this is a frequent value
575 self.frequent
576 .get_(k)
577 .or_else(|| {
578 self.recent
579 .peek_(k)
580 .and_then(|v| self.move_to_frequent(k, v))
581 })
582 .map(|v| unsafe { core::mem::transmute(v) })
583 }
584
585 /// Returns a mutable reference to the value of the key in the cache or `None` if it
586 /// is not present in the cache. Moves the key to the head of the LRU list if it exists.
587 ///
588 /// # Example
589 ///
590 /// ```
591 /// use caches::{Cache, TwoQueueCache};
592 /// let mut cache = TwoQueueCache::new(2).unwrap();
593 ///
594 /// cache.put("apple", 8);
595 /// cache.put("banana", 4);
596 /// cache.put("banana", 6);
597 /// cache.put("pear", 2);
598 ///
599 /// assert_eq!(cache.get_mut(&"apple"), None);
600 /// assert_eq!(cache.get_mut(&"banana"), Some(&mut 6));
601 /// assert_eq!(cache.get_mut(&"pear"), Some(&mut 2));
602 /// ```
603 fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
604 where
605 K: Borrow<Q>,
606 Q: Hash + Eq + ?Sized,
607 {
608 // Check if this is a frequent value
609 self.frequent
610 .get_mut_(k)
611 .or_else(|| {
612 self.recent
613 .peek_mut_(k)
614 .and_then(|v| self.move_to_frequent(k, v))
615 })
616 .map(|v| unsafe { core::mem::transmute(v) })
617 }
618
619 /// Returns a reference to the value corresponding to the key in the cache or `None` if it is
620 /// not present in the cache. Unlike `get`, `peek` does not update the LRU list so the key's
621 /// position will be unchanged.
622 ///
623 /// # Example
624 ///
625 /// ```
626 /// use caches::{Cache, TwoQueueCache};
627 /// let mut cache = TwoQueueCache::new(2).unwrap();
628 ///
629 /// cache.put(1, "a");
630 /// cache.put(2, "b");
631 ///
632 /// assert_eq!(cache.peek(&1), Some(&"a"));
633 /// assert_eq!(cache.peek(&2), Some(&"b"));
634 /// ```
635 fn peek<Q>(&self, k: &Q) -> Option<&V>
636 where
637 K: Borrow<Q>,
638 Q: Hash + Eq + ?Sized,
639 {
640 self.frequent.peek(k).or_else(|| self.recent.peek(k))
641 }
642
643 /// Returns a mutable reference to the value corresponding to the key in the cache or `None`
644 /// if it is not present in the cache. Unlike `get_mut`, `peek_mut` does not update the LRU
645 /// list so the key's position will be unchanged.
646 ///
647 /// # Example
648 ///
649 /// ```
650 /// use caches::{Cache, TwoQueueCache};
651 /// let mut cache = TwoQueueCache::new(2).unwrap();
652 ///
653 /// cache.put(1, "a");
654 /// cache.put(2, "b");
655 ///
656 /// assert_eq!(cache.peek_mut(&1), Some(&mut "a"));
657 /// assert_eq!(cache.peek_mut(&2), Some(&mut "b"));
658 /// ```
659 fn peek_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
660 where
661 K: Borrow<Q>,
662 Q: Hash + Eq + ?Sized,
663 {
664 match self.frequent.peek_mut(k) {
665 Some(v) => Some(v),
666 None => self.recent.peek_mut(k),
667 }
668 }
669
670 /// Removes and returns the value corresponding to the key from the cache or
671 /// `None` if it does not exist.
672 ///
673 /// # Example
674 ///
675 /// ```
676 /// use caches::{Cache, TwoQueueCache};
677 /// let mut cache = TwoQueueCache::new(2).unwrap();
678 ///
679 /// cache.put(2, "a");
680 ///
681 /// assert_eq!(cache.remove(&1), None);
682 /// assert_eq!(cache.remove(&2), Some("a"));
683 /// assert_eq!(cache.remove(&2), None);
684 /// assert_eq!(cache.len(), 0);
685 /// ```
686 fn remove<Q>(&mut self, k: &Q) -> Option<V>
687 where
688 K: Borrow<Q>,
689 Q: Hash + Eq + ?Sized,
690 {
691 self.frequent
692 .remove(k)
693 .or_else(|| self.recent.remove(k))
694 .or_else(|| self.ghost.remove(k))
695 }
696
697 /// Returns a bool indicating whether the given key is in the cache. Does not update the
698 /// LRU list.
699 ///
700 /// # Example
701 ///
702 /// ```
703 /// use caches::{Cache, TwoQueueCache};
704 /// let mut cache = TwoQueueCache::new(2).unwrap();
705 ///
706 /// cache.put(1, "a");
707 /// cache.put(2, "b");
708 /// cache.put(3, "c");
709 ///
710 /// assert!(!cache.contains(&1));
711 /// assert!(cache.contains(&2));
712 /// assert!(cache.contains(&3));
713 /// ```
714 fn contains<Q>(&self, k: &Q) -> bool
715 where
716 K: Borrow<Q>,
717 Q: Hash + Eq + ?Sized,
718 {
719 self.frequent.contains(k) || self.recent.contains(k)
720 }
721
722 /// Clears the contents of the cache.
723 ///
724 /// # Example
725 ///
726 /// ```
727 /// use caches::{Cache, TwoQueueCache};
728 /// let mut cache: TwoQueueCache<isize, &str> = TwoQueueCache::new(2).unwrap();
729 /// assert_eq!(cache.len(), 0);
730 ///
731 /// cache.put(1, "a");
732 /// assert_eq!(cache.len(), 1);
733 ///
734 /// cache.put(2, "b");
735 /// assert_eq!(cache.len(), 2);
736 ///
737 /// cache.purge();
738 /// assert_eq!(cache.len(), 0);
739 /// ```
740 fn purge(&mut self) {
741 self.frequent.purge();
742 self.recent.purge();
743 self.ghost.purge();
744 }
745
746 /// Returns the number of key-value pairs that are currently in the the cache
747 /// (excluding the length of inner ghost LRU).
748 ///
749 /// # Example
750 ///
751 /// ```
752 /// use caches::{Cache, TwoQueueCache};
753 /// let mut cache = TwoQueueCache::new(2).unwrap();
754 /// assert_eq!(cache.len(), 0);
755 ///
756 /// cache.put(1, "a");
757 /// assert_eq!(cache.len(), 1);
758 ///
759 /// cache.put(2, "b");
760 /// assert_eq!(cache.len(), 2);
761 ///
762 /// cache.put(3, "c");
763 /// assert_eq!(cache.len(), 2);
764 /// ```
765 fn len(&self) -> usize {
766 self.recent.len() + self.frequent.len()
767 }
768
769 /// Returns the maximum number of key-value pairs the cache can hold
770 /// (excluding the capacity of inner ghost LRU).
771 ///
772 /// # Example
773 ///
774 /// ```
775 /// use caches::{Cache, TwoQueueCache};
776 /// let mut cache: TwoQueueCache<isize, &str> = TwoQueueCache::new(2).unwrap();
777 /// assert_eq!(cache.cap(), 2);
778 /// ```
779 fn cap(&self) -> usize {
780 self.size
781 }
782
783 fn is_empty(&self) -> bool {
784 self.frequent.is_empty() && self.recent.is_empty() && self.ghost.is_empty()
785 }
786}
787
788impl<K: Hash + Eq, V, RH: BuildHasher, FH: BuildHasher, GH: BuildHasher>
789 TwoQueueCache<K, V, RH, FH, GH>
790{
791 /// Create a [`TwoQueueCache`] from [`TwoQueueCacheBuilder`].
792 ///
793 /// # Example
794 /// ```rust
795 /// use caches::{TwoQueueCacheBuilder, TwoQueueCache, Cache};
796 /// use rustc_hash::FxHasher;
797 /// use std::hash::BuildHasherDefault;
798 ///
799 /// let builder = TwoQueueCacheBuilder::new(5)
800 /// .set_recent_ratio(0.3)
801 /// .set_ghost_ratio(0.4)
802 /// .set_recent_hasher(BuildHasherDefault::<FxHasher>::default())
803 /// .set_frequent_hasher(BuildHasherDefault::<FxHasher>::default())
804 /// .set_ghost_hasher(BuildHasherDefault::<FxHasher>::default());
805 ///
806 /// let mut cache = TwoQueueCache::from_builder(builder).unwrap();
807 /// cache.put(1, 1);
808 /// ```
809 ///
810 /// [`TwoQueueCacheBuilder`]: struct.TwoQueueCacheBuilder.html
811 /// [`TwoQueueCache`]: struct.TwoQueueCache.html
812 pub fn from_builder(builder: TwoQueueCacheBuilder<RH, FH, GH>) -> Result<Self, CacheError> {
813 builder.finalize()
814 }
815
816 /// Returns the number of key-value pairs that are currently in the the recent LRU.
817 pub fn recent_len(&self) -> usize {
818 self.recent.len()
819 }
820
821 /// Returns the number of key-value pairs that are currently in the the frequent LRU.
822 pub fn frequent_len(&self) -> usize {
823 self.frequent.len()
824 }
825
826 /// Returns the number of key-value pairs that are currently in the the ghost LRU.
827 pub fn ghost_len(&self) -> usize {
828 self.ghost.len()
829 }
830
831 /// An iterator visiting all keys of recent LRU in most-recently used order. The iterator element type is
832 /// `&'a K`.
833 ///
834 /// # Examples
835 ///
836 /// ```
837 /// use caches::{Cache, TwoQueueCache};
838 ///
839 /// let mut cache = TwoQueueCache::new(3).unwrap();
840 /// cache.put("a", 1);
841 /// cache.put("b", 2);
842 /// cache.put("c", 3);
843 ///
844 /// for key in cache.recent_keys() {
845 /// println!("key: {}", key);
846 /// }
847 /// ```
848 pub fn recent_keys(&self) -> KeysMRUIter<'_, K, V> {
849 self.recent.keys()
850 }
851
852 /// An iterator visiting all keys of recent LRU in less-recently used order. The iterator element type is
853 /// `&'a K`.
854 ///
855 /// # Examples
856 ///
857 /// ```
858 /// use caches::{Cache, TwoQueueCache};
859 ///
860 /// let mut cache = TwoQueueCache::new(3).unwrap();
861 /// cache.put("a", 1);
862 /// cache.put("b", 2);
863 /// cache.put("c", 3);
864 ///
865 /// for key in cache.recent_keys_lru() {
866 /// println!("key: {}", key);
867 /// }
868 /// ```
869 pub fn recent_keys_lru(&self) -> KeysLRUIter<'_, K, V> {
870 self.recent.keys_lru()
871 }
872
873 /// An iterator visiting all values of recent LRU in most-recently used order. The iterator element type is
874 /// `&'a V`.
875 ///
876 /// # Examples
877 ///
878 /// ```
879 /// use caches::{Cache, TwoQueueCache};
880 ///
881 /// let mut cache = TwoQueueCache::new(3).unwrap();
882 /// cache.put("a", 1);
883 /// cache.put("b", 2);
884 /// cache.put("c", 3);
885 ///
886 /// for val in cache.recent_values() {
887 /// println!("val: {}", val);
888 /// }
889 /// ```
890 pub fn recent_values(&self) -> ValuesMRUIter<'_, K, V> {
891 self.recent.values()
892 }
893
894 /// An iterator visiting all values in less-recently used order. The iterator element type is
895 /// `&'a V`.
896 ///
897 /// # Examples
898 ///
899 /// ```
900 /// use caches::{Cache, TwoQueueCache};
901 ///
902 /// let mut cache = TwoQueueCache::new(3).unwrap();
903 /// cache.put("a", 1);
904 /// cache.put("b", 2);
905 /// cache.put("c", 3);
906 ///
907 /// for val in cache.recent_values_lru() {
908 /// println!("val: {}", val);
909 /// }
910 /// ```
911 pub fn recent_values_lru(&self) -> ValuesLRUIter<'_, K, V> {
912 self.recent.values_lru()
913 }
914
915 /// An iterator visiting all values of recent LRU in most-recently used order. The iterator element type is
916 /// `&'a mut V`.
917 ///
918 /// # Examples
919 ///
920 /// ```
921 /// use caches::{Cache, TwoQueueCache};
922 ///
923 /// let mut cache = TwoQueueCache::new(3).unwrap();
924 /// cache.put("a", 1);
925 /// cache.put("b", 2);
926 /// cache.put("c", 3);
927 ///
928 /// for val in cache.recent_values_mut() {
929 /// println!("val: {}", val);
930 /// }
931 /// ```
932 pub fn recent_values_mut(&mut self) -> ValuesMRUIterMut<'_, K, V> {
933 self.recent.values_mut()
934 }
935
936 /// An iterator visiting all values of recent LRU in less-recently used order. The iterator element type is
937 /// `&'a mut V`.
938 ///
939 /// # Examples
940 ///
941 /// ```
942 /// use caches::{Cache, TwoQueueCache};
943 ///
944 /// let mut cache = TwoQueueCache::new(3).unwrap();
945 /// cache.put("a", 1);
946 /// cache.put("b", 2);
947 /// cache.put("c", 3);
948 ///
949 /// for val in cache.recent_values_lru_mut() {
950 /// println!("val: {}", val);
951 /// }
952 /// ```
953 pub fn recent_values_lru_mut(&mut self) -> ValuesLRUIterMut<'_, K, V> {
954 self.recent.values_lru_mut()
955 }
956
957 /// An iterator visiting all entries of recent LRU in most-recently used order. The iterator element type is
958 /// `(&'a K, &'a V)`.
959 ///
960 /// # Examples
961 ///
962 /// ```
963 /// use caches::{Cache, TwoQueueCache};
964 ///
965 /// let mut cache = TwoQueueCache::new(3).unwrap();
966 /// cache.put("a", 1);
967 /// cache.put("b", 2);
968 /// cache.put("c", 3);
969 ///
970 /// for (key, val) in cache.recent_iter() {
971 /// println!("key: {} val: {}", key, val);
972 /// }
973 /// ```
974 pub fn recent_iter(&self) -> MRUIter<'_, K, V> {
975 self.recent.iter()
976 }
977
978 /// An iterator visiting all entries of recent LRU in less-recently used order. The iterator element type is
979 /// `(&'a K, &'a V)`.
980 ///
981 /// # Examples
982 ///
983 /// ```
984 /// use caches::{Cache, TwoQueueCache};
985 ///
986 /// let mut cache = TwoQueueCache::new(3).unwrap();
987 /// cache.put("a", 1);
988 /// cache.put("b", 2);
989 /// cache.put("c", 3);
990 ///
991 /// for (key, val) in cache.recent_iter_lru() {
992 /// println!("key: {} val: {}", key, val);
993 /// }
994 /// ```
995 pub fn recent_iter_lru(&self) -> LRUIter<'_, K, V> {
996 self.recent.iter_lru()
997 }
998
999 /// An iterator visiting all entries of recent LRU in most-recently-used order, giving a mutable reference on
1000 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1001 ///
1002 /// # Examples
1003 ///
1004 /// ```
1005 /// use caches::{Cache, TwoQueueCache};
1006 ///
1007 /// struct HddBlock {
1008 /// idx: u64,
1009 /// dirty: bool,
1010 /// data: [u8; 512]
1011 /// }
1012 ///
1013 /// let mut cache = TwoQueueCache::new(3).unwrap();
1014 ///
1015 /// // put in recent list
1016 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1017 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1018 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1019 ///
1020 /// let mut ctr = 2i32;
1021 /// // write dirty blocks to disk.
1022 /// for (block_id, block) in cache.recent_iter_mut() {
1023 /// if block.dirty {
1024 /// // write block to disk
1025 /// block.dirty = false
1026 /// }
1027 /// assert_eq!(*block_id, ctr);
1028 /// ctr -= 1;
1029 /// }
1030 /// ```
1031 pub fn recent_iter_mut(&mut self) -> MRUIterMut<'_, K, V> {
1032 self.recent.iter_mut()
1033 }
1034
1035 /// An iterator visiting all entries of recent LRU in less-recently-used order, giving a mutable reference on
1036 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1037 ///
1038 /// # Examples
1039 ///
1040 /// ```
1041 /// use caches::{Cache, TwoQueueCache};
1042 ///
1043 /// struct HddBlock {
1044 /// idx: u64,
1045 /// dirty: bool,
1046 /// data: [u8; 512]
1047 /// }
1048 ///
1049 /// let mut cache = TwoQueueCache::new(3).unwrap();
1050 ///
1051 /// // put in recent list
1052 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1053 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1054 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1055 ///
1056 /// // upgrade to frequent list
1057 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1058 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1059 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1060 ///
1061 /// let mut ctr = 0i32;
1062 ///
1063 /// // write dirty blocks to disk.
1064 /// for (block_id, block) in cache.frequent_iter_lru_mut() {
1065 /// if block.dirty {
1066 /// // write block to disk
1067 /// block.dirty = false
1068 /// }
1069 /// assert_eq!(*block_id, ctr);
1070 /// ctr += 1;
1071 /// }
1072 /// ```
1073 pub fn recent_iter_lru_mut(&mut self) -> LRUIterMut<'_, K, V> {
1074 self.recent.iter_lru_mut()
1075 }
1076
1077 /// An iterator visiting all keys of ghost LRU in most-recently used order. The iterator element type is
1078 /// `&'a K`.
1079 ///
1080 /// # Examples
1081 ///
1082 /// ```
1083 /// use caches::{Cache, TwoQueueCache};
1084 ///
1085 /// let mut cache = TwoQueueCache::new(3).unwrap();
1086 /// cache.put("a", 1);
1087 /// cache.put("b", 2);
1088 /// cache.put("c", 3);
1089 ///
1090 /// for key in cache.ghost_keys() {
1091 /// println!("key: {}", key);
1092 /// }
1093 /// ```
1094 pub fn ghost_keys(&self) -> KeysMRUIter<'_, K, V> {
1095 self.ghost.keys()
1096 }
1097
1098 /// An iterator visiting all keys of ghost LRU in less-recently used order. The iterator element type is
1099 /// `&'a K`.
1100 ///
1101 /// # Examples
1102 ///
1103 /// ```
1104 /// use caches::{Cache, TwoQueueCache};
1105 ///
1106 /// let mut cache = TwoQueueCache::new(3).unwrap();
1107 /// cache.put("a", 1);
1108 /// cache.put("b", 2);
1109 /// cache.put("c", 3);
1110 ///
1111 /// for key in cache.ghost_keys_lru() {
1112 /// println!("key: {}", key);
1113 /// }
1114 /// ```
1115 pub fn ghost_keys_lru(&self) -> KeysLRUIter<'_, K, V> {
1116 self.ghost.keys_lru()
1117 }
1118
1119 /// An iterator visiting all values of ghost LRU in most-recently used order. The iterator element type is
1120 /// `&'a V`.
1121 ///
1122 /// # Examples
1123 ///
1124 /// ```
1125 /// use caches::{Cache, TwoQueueCache};
1126 ///
1127 /// let mut cache = TwoQueueCache::new(3).unwrap();
1128 /// cache.put("a", 1);
1129 /// cache.put("b", 2);
1130 /// cache.put("c", 3);
1131 ///
1132 /// for val in cache.ghost_values() {
1133 /// println!("val: {}", val);
1134 /// }
1135 /// ```
1136 pub fn ghost_values(&self) -> ValuesMRUIter<'_, K, V> {
1137 self.ghost.values()
1138 }
1139
1140 /// An iterator visiting all values in less-recently used order. The iterator element type is
1141 /// `&'a V`.
1142 ///
1143 /// # Examples
1144 ///
1145 /// ```
1146 /// use caches::{Cache, TwoQueueCache};
1147 ///
1148 /// let mut cache = TwoQueueCache::new(3).unwrap();
1149 /// cache.put("a", 1);
1150 /// cache.put("b", 2);
1151 /// cache.put("c", 3);
1152 ///
1153 /// for val in cache.ghost_values_lru() {
1154 /// println!("val: {}", val);
1155 /// }
1156 /// ```
1157 pub fn ghost_values_lru(&self) -> ValuesLRUIter<'_, K, V> {
1158 self.ghost.values_lru()
1159 }
1160
1161 /// An iterator visiting all values of ghost LRU in most-recently used order. The iterator element type is
1162 /// `&'a mut V`.
1163 ///
1164 /// # Examples
1165 ///
1166 /// ```
1167 /// use caches::{Cache, TwoQueueCache};
1168 ///
1169 /// let mut cache = TwoQueueCache::new(3).unwrap();
1170 /// cache.put("a", 1);
1171 /// cache.put("b", 2);
1172 /// cache.put("c", 3);
1173 ///
1174 /// for val in cache.ghost_values_mut() {
1175 /// println!("val: {}", val);
1176 /// }
1177 /// ```
1178 pub fn ghost_values_mut(&mut self) -> ValuesMRUIterMut<'_, K, V> {
1179 self.ghost.values_mut()
1180 }
1181
1182 /// An iterator visiting all values of ghost LRU in less-recently used order. The iterator element type is
1183 /// `&'a mut V`.
1184 ///
1185 /// # Examples
1186 ///
1187 /// ```
1188 /// use caches::{Cache, TwoQueueCache};
1189 ///
1190 /// let mut cache = TwoQueueCache::new(3).unwrap();
1191 /// cache.put("a", 1);
1192 /// cache.put("b", 2);
1193 /// cache.put("c", 3);
1194 ///
1195 /// for val in cache.ghost_values_lru_mut() {
1196 /// println!("val: {}", val);
1197 /// }
1198 /// ```
1199 pub fn ghost_values_lru_mut(&mut self) -> ValuesLRUIterMut<'_, K, V> {
1200 self.ghost.values_lru_mut()
1201 }
1202
1203 /// An iterator visiting all entries of ghost LRU in most-recently used order. The iterator element type is
1204 /// `(&'a K, &'a V)`.
1205 ///
1206 /// # Examples
1207 ///
1208 /// ```
1209 /// use caches::{Cache, TwoQueueCache};
1210 ///
1211 /// let mut cache = TwoQueueCache::new(3).unwrap();
1212 /// cache.put("a", 1);
1213 /// cache.put("b", 2);
1214 /// cache.put("c", 3);
1215 ///
1216 /// for (key, val) in cache.ghost_iter() {
1217 /// println!("key: {} val: {}", key, val);
1218 /// }
1219 /// ```
1220 pub fn ghost_iter(&self) -> MRUIter<'_, K, V> {
1221 self.ghost.iter()
1222 }
1223
1224 /// An iterator visiting all entries of ghost LRU in less-recently used order. The iterator element type is
1225 /// `(&'a K, &'a V)`.
1226 ///
1227 /// # Examples
1228 ///
1229 /// ```
1230 /// use caches::{Cache, TwoQueueCache};
1231 ///
1232 /// let mut cache = TwoQueueCache::new(3).unwrap();
1233 /// cache.put("a", 1);
1234 /// cache.put("b", 2);
1235 /// cache.put("c", 3);
1236 ///
1237 /// for (key, val) in cache.ghost_iter_lru() {
1238 /// println!("key: {} val: {}", key, val);
1239 /// }
1240 /// ```
1241 pub fn ghost_iter_lru(&self) -> LRUIter<'_, K, V> {
1242 self.ghost.iter_lru()
1243 }
1244
1245 /// An iterator visiting all entries of ghost LRU in most-recently-used order, giving a mutable reference on
1246 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1247 ///
1248 /// # Examples
1249 ///
1250 /// ```
1251 /// use caches::{Cache, TwoQueueCache};
1252 ///
1253 /// struct HddBlock {
1254 /// idx: u64,
1255 /// dirty: bool,
1256 /// data: [u8; 512]
1257 /// }
1258 ///
1259 /// let mut cache = TwoQueueCache::new(3).unwrap();
1260 ///
1261 /// // put in recent list
1262 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1263 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1264 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1265 ///
1266 /// // upgrade to frequent list
1267 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1268 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1269 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1270 ///
1271 /// let mut ctr = 2i32;
1272 /// // write dirty blocks to disk.
1273 /// for (block_id, block) in cache.ghost_iter_mut() {
1274 /// if block.dirty {
1275 /// // write block to disk
1276 /// block.dirty = false
1277 /// }
1278 /// assert_eq!(*block_id, ctr);
1279 /// ctr -= 1;
1280 /// }
1281 /// ```
1282 pub fn ghost_iter_mut(&mut self) -> MRUIterMut<'_, K, V> {
1283 self.ghost.iter_mut()
1284 }
1285
1286 /// An iterator visiting all entries of ghost LRU in less-recently-used order, giving a mutable reference on
1287 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1288 ///
1289 /// # Examples
1290 ///
1291 /// ```
1292 /// use caches::{Cache, TwoQueueCache};
1293 ///
1294 /// struct HddBlock {
1295 /// idx: u64,
1296 /// dirty: bool,
1297 /// data: [u8; 512]
1298 /// }
1299 ///
1300 /// let mut cache = TwoQueueCache::new(3).unwrap();
1301 ///
1302 /// // put in recent list
1303 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1304 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1305 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1306 ///
1307 /// // upgrade to frequent list
1308 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1309 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1310 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1311 ///
1312 /// let mut ctr = 0i32;
1313 ///
1314 /// // write dirty blocks to disk.
1315 /// for (block_id, block) in cache.frequent_iter_lru_mut() {
1316 /// if block.dirty {
1317 /// // write block to disk
1318 /// block.dirty = false
1319 /// }
1320 /// assert_eq!(*block_id, ctr);
1321 /// ctr += 1;
1322 /// }
1323 /// ```
1324 pub fn ghost_iter_lru_mut(&mut self) -> LRUIterMut<'_, K, V> {
1325 self.ghost.iter_lru_mut()
1326 }
1327
1328 /// An iterator visiting all keys of frequent LRU in most-recently used order. The iterator element type is
1329 /// `&'a K`.
1330 ///
1331 /// # Examples
1332 ///
1333 /// ```
1334 /// use caches::{Cache, TwoQueueCache};
1335 ///
1336 /// let mut cache = TwoQueueCache::new(3).unwrap();
1337 /// cache.put("a", 1);
1338 /// cache.put("b", 2);
1339 /// cache.put("c", 3);
1340 ///
1341 /// for key in cache.frequent_keys() {
1342 /// println!("key: {}", key);
1343 /// }
1344 /// ```
1345 pub fn frequent_keys(&self) -> KeysMRUIter<'_, K, V> {
1346 self.frequent.keys()
1347 }
1348
1349 /// An iterator visiting all keys of frequent LRU in less-recently used order. The iterator element type is
1350 /// `&'a K`.
1351 ///
1352 /// # Examples
1353 ///
1354 /// ```
1355 /// use caches::{Cache, TwoQueueCache};
1356 ///
1357 /// let mut cache = TwoQueueCache::new(3).unwrap();
1358 /// cache.put("a", 1);
1359 /// cache.put("b", 2);
1360 /// cache.put("c", 3);
1361 ///
1362 /// for key in cache.frequent_keys_lru() {
1363 /// println!("key: {}", key);
1364 /// }
1365 /// ```
1366 pub fn frequent_keys_lru(&self) -> KeysLRUIter<'_, K, V> {
1367 self.frequent.keys_lru()
1368 }
1369
1370 /// An iterator visiting all values of frequent LRU in most-recently used order. The iterator element type is
1371 /// `&'a V`.
1372 ///
1373 /// # Examples
1374 ///
1375 /// ```
1376 /// use caches::{Cache, TwoQueueCache};
1377 ///
1378 /// let mut cache = TwoQueueCache::new(3).unwrap();
1379 /// cache.put("a", 1);
1380 /// cache.put("b", 2);
1381 /// cache.put("c", 3);
1382 ///
1383 /// for val in cache.frequent_values() {
1384 /// println!("val: {}", val);
1385 /// }
1386 /// ```
1387 pub fn frequent_values(&self) -> ValuesMRUIter<'_, K, V> {
1388 self.frequent.values()
1389 }
1390
1391 /// An iterator visiting all values of frequent LRU in less-recently used order. The iterator element type is
1392 /// `&'a V`.
1393 ///
1394 /// # Examples
1395 ///
1396 /// ```
1397 /// use caches::{Cache, TwoQueueCache};
1398 ///
1399 /// let mut cache = TwoQueueCache::new(3).unwrap();
1400 /// cache.put("a", 1);
1401 /// cache.put("b", 2);
1402 /// cache.put("c", 3);
1403 ///
1404 /// for val in cache.frequent_values_lru() {
1405 /// println!("val: {}", val);
1406 /// }
1407 /// ```
1408 pub fn frequent_values_lru(&self) -> ValuesLRUIter<'_, K, V> {
1409 self.frequent.values_lru()
1410 }
1411
1412 /// An iterator visiting all values of frequent LRU in most-recently used order. The iterator element type is
1413 /// `&'a mut V`.
1414 ///
1415 /// # Examples
1416 ///
1417 /// ```
1418 /// use caches::{Cache, TwoQueueCache};
1419 ///
1420 /// let mut cache = TwoQueueCache::new(3).unwrap();
1421 /// cache.put("a", 1);
1422 /// cache.put("b", 2);
1423 /// cache.put("c", 3);
1424 ///
1425 /// for val in cache.frequent_values_mut() {
1426 /// println!("val: {}", val);
1427 /// }
1428 /// ```
1429 pub fn frequent_values_mut(&mut self) -> ValuesMRUIterMut<'_, K, V> {
1430 self.frequent.values_mut()
1431 }
1432
1433 /// An iterator visiting all values of frequent LRU in less-recently used order. The iterator element type is
1434 /// `&'a mut V`.
1435 ///
1436 /// # Examples
1437 ///
1438 /// ```
1439 /// use caches::{Cache, TwoQueueCache};
1440 ///
1441 /// let mut cache = TwoQueueCache::new(3).unwrap();
1442 /// cache.put("a", 1);
1443 /// cache.put("b", 2);
1444 /// cache.put("c", 3);
1445 ///
1446 /// for val in cache.frequent_values_lru_mut() {
1447 /// println!("val: {}", val);
1448 /// }
1449 /// ```
1450 pub fn frequent_values_lru_mut(&mut self) -> ValuesLRUIterMut<'_, K, V> {
1451 self.frequent.values_lru_mut()
1452 }
1453
1454 /// An iterator visiting all entries of frequent LRU in most-recently used order. The iterator element type is
1455 /// `(&'a K, &'a V)`.
1456 ///
1457 /// # Examples
1458 ///
1459 /// ```
1460 /// use caches::{Cache, TwoQueueCache};
1461 ///
1462 /// let mut cache = TwoQueueCache::new(3).unwrap();
1463 /// cache.put("a", 1);
1464 /// cache.put("b", 2);
1465 /// cache.put("c", 3);
1466 ///
1467 /// for (key, val) in cache.frequent_iter() {
1468 /// println!("key: {} val: {}", key, val);
1469 /// }
1470 /// ```
1471 pub fn frequent_iter(&self) -> MRUIter<'_, K, V> {
1472 self.frequent.iter()
1473 }
1474
1475 /// An iterator visiting all entries of frequent LRU in less-recently used order. The iterator element type is
1476 /// `(&'a K, &'a V)`.
1477 ///
1478 /// # Examples
1479 ///
1480 /// ```
1481 /// use caches::{Cache, TwoQueueCache};
1482 ///
1483 /// let mut cache = TwoQueueCache::new(3).unwrap();
1484 /// cache.put("a", 1);
1485 /// cache.put("b", 2);
1486 /// cache.put("c", 3);
1487 ///
1488 /// for (key, val) in cache.frequent_iter_lru() {
1489 /// println!("key: {} val: {}", key, val);
1490 /// }
1491 /// ```
1492 pub fn frequent_iter_lru(&self) -> LRUIter<'_, K, V> {
1493 self.frequent.iter_lru()
1494 }
1495
1496 /// An iterator visiting all entries of frequent LRU in most-recently-used order, giving a mutable reference on
1497 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1498 ///
1499 /// # Examples
1500 ///
1501 /// ```
1502 /// use caches::{Cache, TwoQueueCache};
1503 ///
1504 /// struct HddBlock {
1505 /// idx: u64,
1506 /// dirty: bool,
1507 /// data: [u8; 512]
1508 /// }
1509 ///
1510 /// let mut cache = TwoQueueCache::new(3).unwrap();
1511 ///
1512 /// // put in recent list
1513 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1514 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1515 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1516 ///
1517 /// // upgrade to frequent list
1518 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1519 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1520 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1521 ///
1522 /// let mut ctr = 2i32;
1523 /// // write dirty blocks to disk.
1524 /// for (block_id, block) in cache.frequent_iter_mut() {
1525 /// if block.dirty {
1526 /// // write block to disk
1527 /// block.dirty = false
1528 /// }
1529 /// assert_eq!(*block_id, ctr);
1530 /// ctr -= 1;
1531 /// }
1532 /// ```
1533 pub fn frequent_iter_mut(&mut self) -> MRUIterMut<'_, K, V> {
1534 self.frequent.iter_mut()
1535 }
1536
1537 /// An iterator visiting all entries of frequent LRU in less-recently-used order, giving a mutable reference on
1538 /// V. The iterator element type is `(&'a K, &'a mut V)`.
1539 ///
1540 /// # Examples
1541 ///
1542 /// ```
1543 /// use caches::{Cache, TwoQueueCache};
1544 ///
1545 /// struct HddBlock {
1546 /// idx: u64,
1547 /// dirty: bool,
1548 /// data: [u8; 512]
1549 /// }
1550 ///
1551 /// let mut cache = TwoQueueCache::new(3).unwrap();
1552 ///
1553 /// // put in recent list
1554 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1555 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1556 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1557 ///
1558 /// // upgrade to frequent list
1559 /// cache.put(0, HddBlock { idx: 0, dirty: false, data: [0x00; 512]});
1560 /// cache.put(1, HddBlock { idx: 1, dirty: true, data: [0x55; 512]});
1561 /// cache.put(2, HddBlock { idx: 2, dirty: true, data: [0x77; 512]});
1562 ///
1563 /// let mut ctr = 0i32;
1564 ///
1565 /// // write dirty blocks to disk.
1566 /// for (block_id, block) in cache.frequent_iter_lru_mut() {
1567 /// if block.dirty {
1568 /// // write block to disk
1569 /// block.dirty = false
1570 /// }
1571 /// assert_eq!(*block_id, ctr);
1572 /// ctr += 1;
1573 /// }
1574 /// ```
1575 pub fn frequent_iter_lru_mut(&mut self) -> LRUIterMut<'_, K, V> {
1576 self.frequent.iter_lru_mut()
1577 }
1578
1579 fn move_to_frequent<T, Q>(&mut self, k: &Q, v: T) -> Option<T>
1580 where
1581 K: Borrow<Q>,
1582 Q: Hash + Eq + ?Sized,
1583 {
1584 // remove the element from the recent LRU
1585 // and put it in frequent LRU.
1586 if let Some(ent) = self.recent.remove_and_return_ent(k) {
1587 match self.frequent.put_or_evict_nonnull(ent) {
1588 None => Some(v),
1589 // the Some branch will not reach, because we remove one from
1590 // recent LRU, and add this one to frequent LRU, the total size
1591 // of the cache is not changed. We still keep this for good measure.
1592 Some(_) => Some(v),
1593 }
1594 } else {
1595 None
1596 }
1597 }
1598}
1599
1600impl<K: Hash + Eq, V, RH: BuildHasher, FH: BuildHasher, GH: BuildHasher> fmt::Debug
1601 for TwoQueueCache<K, V, RH, FH, GH>
1602{
1603 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1604 f.debug_struct("TwoQueueCache")
1605 .field("len", &self.len())
1606 .field("cap", &self.cap())
1607 .finish()
1608 }
1609}
1610
1611#[cfg(test)]
1612mod test {
1613 use crate::lru::two_queue::TwoQueueCache;
1614 use crate::lru::CacheError;
1615 use crate::{Cache, PutResult};
1616 use alloc::vec::Vec;
1617 use rand::seq::SliceRandom;
1618 use rand::{thread_rng, Rng};
1619 use std::format;
1620
1621 #[cfg_attr(miri, ignore)]
1622 #[test]
1623 fn test_2q_cache_random_ops() {
1624 let size = 128;
1625 let mut rng = thread_rng();
1626 let mut cases: Vec<u64> = (0..200_000).collect();
1627 cases.shuffle(&mut rng);
1628
1629 let mut cache = TwoQueueCache::new(size).unwrap();
1630
1631 (0..200_000).for_each(|_i| {
1632 let k = rng.gen::<i64>() % 512;
1633 let r: i64 = rng.gen();
1634
1635 match r % 3 {
1636 0 => {
1637 let _ = cache.put(k, k);
1638 }
1639 1 => {
1640 let _ = cache.get(&k);
1641 }
1642 2 => {
1643 let _ = cache.remove(&k);
1644 }
1645 _ => {}
1646 }
1647
1648 assert!(cache.recent.len() + cache.frequent.len() <= size)
1649 })
1650 }
1651
1652 #[test]
1653 fn test_cache_error() {
1654 let cache = TwoQueueCache::<usize, usize>::with_ghost_ratio(0, 3.0).unwrap_err();
1655 assert_eq!(CacheError::InvalidSize(0), cache);
1656
1657 let cache = TwoQueueCache::<usize, usize>::with_ghost_ratio(3, 3.0).unwrap_err();
1658 assert_eq!(CacheError::InvalidGhostRatio(3.0), cache);
1659
1660 let cache = TwoQueueCache::<usize, usize>::with_recent_ratio(3, 3.0).unwrap_err();
1661 assert_eq!(CacheError::InvalidRecentRatio(3.0), cache);
1662 }
1663
1664 #[test]
1665 fn test_2q_cache_get_recent_to_freq() {
1666 let mut cache = TwoQueueCache::new(128).unwrap();
1667 (0..128).for_each(|i| {
1668 let _ = cache.put(i, i);
1669 });
1670
1671 assert_eq!(cache.recent.len(), 128);
1672 assert_eq!(cache.frequent.len(), 0);
1673
1674 (0..128).for_each(|i| {
1675 let v = cache.get(&i);
1676 assert_ne!(v, None, "missing: {}", i);
1677 });
1678
1679 assert_eq!(cache.recent.len(), 0);
1680 assert_eq!(cache.frequent.len(), 128);
1681 }
1682
1683 #[test]
1684 fn test_2q_cache_put_recent_to_freq() {
1685 let mut cache = TwoQueueCache::new(128).unwrap();
1686
1687 // Add initially to recent
1688 cache.put(1, 1);
1689 assert_eq!(cache.recent.len(), 1);
1690 assert_eq!(cache.frequent.len(), 0);
1691
1692 // Add should upgrade to frequent
1693 cache.put(1, 1);
1694 assert_eq!(cache.recent.len(), 0);
1695 assert_eq!(cache.frequent.len(), 1);
1696
1697 // Add should remain in frequent
1698 cache.put(1, 1);
1699 assert_eq!(cache.recent.len(), 0);
1700 assert_eq!(cache.frequent.len(), 1);
1701 }
1702
1703 #[test]
1704 fn test_2q_cache_put() {
1705 let mut cache = TwoQueueCache::new(4).unwrap();
1706
1707 // Add 1,2,3,4,5 -> Evict 1
1708 cache.put(1, 1);
1709 cache.put(2, 2);
1710 cache.put(3, 3);
1711 cache.put(4, 4);
1712 cache.put(5, 5);
1713 assert_eq!(cache.recent.len(), 4);
1714 assert_eq!(cache.ghost.len(), 1,);
1715 assert_eq!(cache.frequent.len(), 0);
1716
1717 // Pull in the recently evicted
1718 assert_eq!(cache.put(1, 1), PutResult::Update(1));
1719 assert_eq!(cache.recent.len(), 3);
1720 assert_eq!(cache.ghost.len(), 1,);
1721 assert_eq!(cache.frequent.len(), 1);
1722
1723 // Add 6, should cause another recent evict
1724 assert_eq!(
1725 format!("{:?}", cache.put(6, 6).clone()),
1726 format!("{:?}", PutResult::<i32, i32>::Put)
1727 );
1728 assert_eq!(cache.recent.len(), 3);
1729 assert_eq!(cache.ghost.len(), 2,);
1730 assert_eq!(cache.frequent.len(), 1);
1731
1732 // Add 7, should evict an entry from ghost LRU.
1733 assert_eq!(cache.put(7, 7), PutResult::Evicted { key: 2, value: 2 });
1734 assert_eq!(cache.recent.len(), 3);
1735 assert_eq!(cache.ghost.len(), 2,);
1736 assert_eq!(cache.frequent.len(), 1);
1737
1738 // Add 2, should evict an entry from ghost LRU
1739 assert_eq!(
1740 format!("{:?}", cache.put(2, 11).clone()),
1741 format!("{:?}", PutResult::Evicted { key: 3, value: 3 })
1742 );
1743 assert_eq!(cache.recent.len(), 3);
1744 assert_eq!(cache.ghost.len(), 2,);
1745 assert_eq!(cache.frequent.len(), 1);
1746
1747 // Add 4, should put the entry from ghost LRU to freq LRU
1748 assert_eq!(cache.put(4, 11), PutResult::Update(4));
1749 assert_eq!(cache.recent.len(), 2);
1750 assert_eq!(cache.ghost.len(), 2,);
1751 assert_eq!(cache.frequent.len(), 2);
1752
1753 // move all entry in recent to freq.
1754 assert_eq!(cache.put(2, 22).clone(), PutResult::Update(11));
1755 assert_eq!(cache.recent.len(), 1);
1756 assert_eq!(cache.ghost.len(), 2,);
1757 assert_eq!(cache.frequent.len(), 3);
1758
1759 assert_eq!(
1760 format!("{:?}", cache.put(7, 77)),
1761 format!("{:?}", PutResult::<i32, i32>::Update(7))
1762 );
1763 assert_eq!(cache.recent.len(), 0);
1764 assert_eq!(cache.ghost.len(), 2);
1765 assert_eq!(cache.frequent.len(), 4);
1766
1767 // Add 6, should put the entry from ghost LRU to freq LRU, and evicted one
1768 // entry
1769 assert_eq!(
1770 format!("{:?}", cache.put(6, 66).clone()),
1771 format!(
1772 "{:?}",
1773 PutResult::EvictedAndUpdate {
1774 evicted: (5, 5),
1775 update: 6
1776 }
1777 )
1778 );
1779 assert_eq!(cache.recent.len(), 0);
1780 assert_eq!(cache.ghost.len(), 1);
1781 assert_eq!(cache.frequent.len(), 4);
1782 }
1783
1784 #[test]
1785 fn test_2q_cache() {
1786 let mut cache = TwoQueueCache::new(128).unwrap();
1787
1788 (0..256u64).for_each(|i| {
1789 cache.put(i, i);
1790 });
1791
1792 assert_eq!(cache.len(), 128);
1793
1794 let rst = cache
1795 .frequent
1796 .keys_lru()
1797 .chain(cache.recent.keys_lru())
1798 .enumerate()
1799 .map(|(idx, k)| (idx as u64, *k))
1800 .collect::<Vec<(u64, u64)>>();
1801
1802 rst.into_iter().for_each(|(idx, k)| match cache.get(&k) {
1803 None => panic!("bad: {}", k),
1804 Some(val) => assert_eq!(*val, idx + 128),
1805 });
1806
1807 (0..128).for_each(|k| {
1808 assert_eq!(cache.get(&k), None);
1809 });
1810
1811 (128..256).for_each(|k| {
1812 assert_ne!(cache.get(&k), None);
1813 });
1814
1815 (128..192).for_each(|k| {
1816 cache.remove(&k);
1817 assert_eq!(cache.get(&k), None);
1818 });
1819
1820 cache.purge();
1821 assert_eq!(cache.len(), 0);
1822 assert_eq!(cache.get(&200), None);
1823 }
1824
1825 #[test]
1826 fn test_2q_cache_contains() {
1827 let mut cache = TwoQueueCache::new(2).unwrap();
1828 cache.put(1, 1);
1829 cache.put(2, 2);
1830
1831 assert!(cache.contains(&1));
1832 cache.put(3, 3);
1833 assert!(
1834 !cache.contains(&1),
1835 "should be in ghost LRU, and the elements in the ghost is not counted as in cache"
1836 );
1837 }
1838
1839 #[test]
1840 fn test_2q_cache_peek() {
1841 let mut cache = TwoQueueCache::new(2).unwrap();
1842 cache.put(1, 1);
1843 cache.put(2, 2);
1844
1845 assert_eq!(cache.peek(&1), Some(&1));
1846 cache.put(3, 3);
1847 assert!(!cache.contains(&1));
1848 }
1849}