1use std::{borrow::Borrow, hash::BuildHasher};
2
3use crate::{
4 cache::{DefaultLifecycle, Lifecycle},
5 Cache, One, Weigher,
6};
7
8#[derive(Debug)]
9pub struct SegmentedCache<
10 K,
11 V,
12 S: BuildHasher = std::hash::RandomState,
13 W: Weigher<K, V> = One,
14 L: Lifecycle<K, V> = DefaultLifecycle,
15> {
16 #[allow(clippy::type_complexity)]
17 segments: Vec<k_lock::Mutex<Cache<K, V, S, W, L>>>,
18 hasher: S,
19}
20
21impl<K, V, S, W, L> SegmentedCache<K, V, S, W, L>
22where
23 K: Eq + std::hash::Hash + Clone,
24 V: Clone,
25 S: BuildHasher + Default,
26 W: Weigher<K, V> + Clone,
27 L: Lifecycle<K, V> + Default,
28{
29 pub fn new(segments: usize, max_weight: usize) -> Self {
30 let weight_per_segment = max_weight / segments;
31 let segments = (0..segments)
32 .map(|_| {
33 k_lock::Mutex::new(Cache::new_with_lifecycle(
34 S::default(),
35 weight_per_segment,
36 L::default(),
37 ))
38 })
39 .collect();
40 Self {
41 segments,
42 hasher: S::default(),
43 }
44 }
45}
46
47impl<K, V, S, W, L> SegmentedCache<K, V, S, W, L>
48where
49 K: Eq + std::hash::Hash + Clone,
50 V: Clone,
51 S: BuildHasher + Default,
52 W: Weigher<K, V> + Clone,
53 L: Lifecycle<K, V> + Clone,
54{
55 pub fn new_with_lifecycle(segments: usize, max_weight: usize, lifecycle: L) -> Self {
56 let weight_per_segment = max_weight / segments;
57 let segments = (0..segments)
58 .map(|_| {
59 k_lock::Mutex::new(Cache::new_with_lifecycle(
60 S::default(),
61 weight_per_segment,
62 lifecycle.clone(),
63 ))
64 })
65 .collect();
66 Self {
67 segments,
68 hasher: S::default(),
69 }
70 }
71
72 pub fn put(&self, key: K, value: V) {
73 let slot = self.hasher.hash_one(&key) as usize % self.segments.len();
74 self.segments[slot]
75 .lock()
76 .expect("mutex must not be poisoned")
77 .put(key, value)
78 }
79
80 pub fn remove(&self, key: &K) -> Option<V> {
81 let slot = self.hasher.hash_one(key) as usize % self.segments.len();
82 self.segments[slot]
83 .lock()
84 .expect("mutex must not be poisoned")
85 .remove(key)
86 }
87
88 pub fn get<Q>(&self, key: &Q) -> Option<V>
89 where
90 K: Borrow<Q>,
91 Q: std::hash::Hash + Eq + ?Sized,
92 {
93 let slot = self.hasher.hash_one(key) as usize % self.segments.len();
94 self.segments[slot]
95 .lock()
96 .expect("mutex must not be poisoned")
97 .get(key)
98 .cloned()
99 }
100 pub fn evict_all(&self) {
115 for segment in &self.segments {
116 segment
117 .lock()
118 .expect("mutex must not be poisoned")
119 .evict_all();
120 }
121 }
122}