Synchronous caches are defined in the moka::sync module. They are thread-safe and can be shared across threads by cloning the cache instance (which is a cheap operation).
Common operations include:
insert(key, value): Manually add an entry.get(&key): Retrieve a value (returns Option<V>, providing a clone of the stored value).invalidate(&key): Manually remove an entry.get_with(key, loader): Atomically initialize and insert a value if the key is not present.try_get_with(key, loader): Similar to get_with but returns a Result.
Note: v0.12.0 introduced major breaking changes. Refer to MIGRATION-GUIDE.md if upgrading from older versions.
use moka::sync::Cache;
use std::thread;
fn value(n: usize) -> String {
format!("value {n}")
}
fn main() {
const NUM_THREADS: usize = 16;
const NUM_KEYS_PER_THREAD: usize = 64;
// Create a cache that can store up to 10,000 entries.
let cache = Cache::new(10_000);
// Spawn threads and read and update the cache simultaneously.
let threads: Vec<_> = (0..NUM_THREADS)
.map(|i| {
// To share the same cache across the threads, clone it.
let my_cache = cache.clone();
let start = i * NUM_KEYS_PER_THREAD;
let end = (i + 1) * NUM_KEYS_PER_THREAD;
thread::spawn(move || {
for key in start..end {
my_cache.insert(key, value(key));
assert_eq!(my_cache.get(&key), Some(value(key)));
}
for key in (start..end).step_by(4) {
my_cache.invalidate(&key);
}
})
})
.collect();
threads.into_iter().for_each(|t| t.join().expect("Failed"));
for key in 0..(NUM_THREADS * NUM_KEYS_PER_THREAD) {
if key % 4 == 0 {
assert_eq!(cache.get(&key), None);
} else {
assert_eq!(cache.get(&key), Some(value(key)));
}
}
}