1pub mod admission;
2pub mod clock;
3pub mod core;
4pub mod metrics;
5pub mod s3fifo;
6
7pub use crate::admission::{AdmissionPolicy, AlwaysAdmission, FrequentPolicy};
8use crate::core::engine::CacheEngine;
9use crate::core::entry_ref::Ref;
10use crate::core::key::Key;
11use crate::metrics::MetricsSnapshot;
12pub use omega_cache_macros::cache;
13use std::borrow::Borrow;
14use std::hash::Hash;
15use std::marker::PhantomData;
16
17pub struct Cache<E, K, V, P>
18where
19 E: CacheEngine<K, V>,
20 K: Eq + Hash,
21 P: AdmissionPolicy<K>,
22{
23 engine: E,
24 admission_policy: P,
25 _phantom: PhantomData<(K, V)>,
26}
27
28impl<E, K, V, A> Cache<E, K, V, A>
29where
30 E: CacheEngine<K, V>,
31 K: Eq + Hash,
32 A: AdmissionPolicy<K>,
33{
34 pub fn new(engine: E, admission_policy: A) -> Self {
35 Self {
36 engine,
37 admission_policy,
38 _phantom: Default::default(),
39 }
40 }
41
42 pub fn get<Q>(&self, key: &Q) -> Option<Ref<K, V>>
48 where
49 Key<K>: Borrow<Q>,
50 Q: Eq + Hash,
51 {
52 self.admission_policy.record(key);
53 self.engine.get(key)
54 }
55
56 pub fn insert(&self, key: K, value: V) {
64 self.engine
65 .insert_with(key, value, None, |incoming, victim| {
66 self.admission_policy.admit(incoming, victim)
67 })
68 }
69
70 pub fn remove<Q>(&self, key: &Q) -> bool
74 where
75 Key<K>: Borrow<Q>,
76 Q: Eq + Hash,
77 {
78 self.engine.remove(key)
79 }
80
81 pub fn metrics(&self) -> MetricsSnapshot {
82 self.engine.metrics()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use crate::cache;
89 use crate::core::backoff::BackoffPolicy;
90 use crate::core::utils::random_string_with_len;
91 use std::thread::scope;
92
93 #[test]
94 fn test_cache_should_create_s3fifo_and_run_workload() {
95 let num_threads = 16;
96 let op_per_thread = 10000;
97
98 let cache = cache!(
99 engine: S3FIFO {
100 capacity: 10000,
101 backoff: { policy: BackoffPolicy::Exponential, limit: 10 },
102 metrics: { shards: 8, latency_samples: 1024 },
103 },
104 admission: Frequent {
105 count_min_sketch: { width: 1024, depth: 4 },
106 decay_threshold: 1000
107 }
108 );
109
110 scope(|scope| {
111 for _ in 0..num_threads {
112 scope.spawn(|| {
113 for _ in 0..op_per_thread {
114 let key = random_string_with_len(10);
115 let value = random_string_with_len(255);
116 cache.insert(key, value);
117 }
118 });
119 }
120 });
121 }
122
123 #[test]
124 fn test_cache_should_create_clock_cache_and_run_workload() {
125 let num_threads = 16;
126 let op_per_thread = 10000;
127
128 let cache = cache!(
129 engine: S3FIFO {
130 capacity: 10000,
131 backoff: { policy: BackoffPolicy::Exponential, limit: 10 },
132 metrics: { shards: 8, latency_samples: 1024 },
133 },
134 admission: Frequent {
135 count_min_sketch: { width: 1024, depth: 4 },
136 decay_threshold: 1000
137 }
138 );
139
140 scope(|scope| {
141 for _ in 0..num_threads {
142 scope.spawn(|| {
143 for _ in 0..op_per_thread {
144 let key = random_string_with_len(10);
145 let value = random_string_with_len(255);
146 cache.insert(key, value);
147 }
148 });
149 }
150 });
151 }
152}