Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ jobs:
with:
command: clippy
args: -- -D warnings
- name: Install dependencies for tools
run: sudo apt-get -y install libfontconfig1-dev jq
- name: Check tools
working-directory: tools
run: cargo clippy -- -D warnings

miri:
runs-on: ubuntu-latest
Expand Down
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/target
/Cargo.lock
cache_memory_used.png
**/target
**/Cargo.lock
**/cache_memory_used.png
6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "quick_cache"
version = "0.6.16"
edition = "2021"
edition = "2024"
description = "Lightweight and high performance concurrent cache"
repository = "https://github.com/arthurprs/quick-cache"
authors = ["Arthur Silva <arthurprs@gmail.com>"]
Expand All @@ -10,7 +10,7 @@ keywords = ["lru", "concurrent", "cache", "s3-fifo", "clock"]
categories = ["caching", "concurrency", "data-structures"]
readme = "README.md"
exclude = ["fuzz"]
rust-version = "1.71"
rust-version = "1.85"

[features]
default = ["ahash", "parking_lot"]
Expand All @@ -29,8 +29,6 @@ criterion = "0.7"
rand = { version = "0.9", features = ["small_rng"] }
rand_distr = "0.5"
tokio = { version = "1", features = ["full"] }
memory-stats = { version = "1.2.0" }
plotters = { version = "0.3" }

[[bench]]
name = "benchmarks"
Expand Down
2 changes: 1 addition & 1 deletion benches/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
use quick_cache::sync::Cache;
use rand::prelude::*;
use rand_distr::Zipf;
Expand Down
4 changes: 2 additions & 2 deletions benches/placeholder_async_bench.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
use quick_cache::sync::Cache;
use std::sync::atomic::{self, AtomicUsize};
use std::sync::Arc;
use std::sync::atomic::{self, AtomicUsize};
use tokio::sync::Barrier;

fn placeholder_async_contention_bench(c: &mut Criterion) {
Expand Down
4 changes: 2 additions & 2 deletions benches/placeholder_bench.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
use quick_cache::sync::{Cache, GuardResult};
use std::sync::atomic::{self, AtomicUsize};
use std::sync::Barrier;
use std::sync::atomic::{self, AtomicUsize};
use std::thread;

fn placeholder_contention_bench(c: &mut Criterion) {
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_weight.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use quick_cache::{sync::Cache, Weighter};
use quick_cache::{Weighter, sync::Cache};

#[derive(Clone)]
struct StringWeighter;
Expand Down
2 changes: 1 addition & 1 deletion examples/equivalent.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use quick_cache::{sync::Cache, Equivalent};
use quick_cache::{Equivalent, sync::Cache};

#[derive(Debug, Hash)]
pub struct Pair<A, B>(pub A, pub B);
Expand Down
2 changes: 1 addition & 1 deletion examples/eviction_listener.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use quick_cache::{sync::Cache, DefaultHashBuilder, Lifecycle, UnitWeighter};
use quick_cache::{DefaultHashBuilder, Lifecycle, UnitWeighter, sync::Cache};
use std::{sync::mpsc, thread};

#[derive(Debug, Clone)]
Expand Down
14 changes: 3 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl MemoryUsed {
mod tests {
use std::{
hash::Hash,
sync::{atomic::AtomicUsize, Arc},
sync::{Arc, atomic::AtomicUsize},
time::Duration,
};

Expand Down Expand Up @@ -325,11 +325,7 @@ mod tests {
wg.wait();
let result = cache.get_or_insert_with(&(1, 1), || {
let before = entered.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if before == solve_at {
Ok(1)
} else {
Err(())
}
if before == solve_at { Ok(1) } else { Err(()) }
});
assert!(matches!(result, Ok(1) | Err(())));
});
Expand Down Expand Up @@ -531,11 +527,7 @@ mod tests {
let result = cache
.get_or_insert_async(&(1, 1), async {
let before = entered.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if before == solve_at {
Ok(1)
} else {
Err(())
}
if before == solve_at { Ok(1) } else { Err(()) }
})
.await;
assert!(matches!(result, Ok(1) | Err(())));
Expand Down
16 changes: 10 additions & 6 deletions src/linked_slab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,21 @@ impl<T> LinkedSlab<T> {
/// Gets an entry and a token to the next entry w/o checking, thus unsafe.
#[inline]
pub unsafe fn get_unchecked(&self, index: Token) -> (&T, Token) {
let entry = self.entries.get_unchecked((index.get() - 1) as usize);
let v = entry.item.as_ref().unwrap_unchecked();
(v, entry.next)
unsafe {
let entry = self.entries.get_unchecked((index.get() - 1) as usize);
let v = entry.item.as_ref().unwrap_unchecked();
(v, entry.next)
}
}

/// Gets an entry and a token to the next entry w/o checking, thus unsafe.
#[inline]
pub unsafe fn get_mut_unchecked(&mut self, index: Token) -> (&mut T, Token) {
let entry = self.entries.get_unchecked_mut((index.get() - 1) as usize);
let v = entry.item.as_mut().unwrap_unchecked();
(v, entry.next)
unsafe {
let entry = self.entries.get_unchecked_mut((index.get() - 1) as usize);
let v = entry.item.as_mut().unwrap_unchecked();
(v, entry.next)
}
}

/// Links an entry before `target_head`. Returns the item next to the linked item,
Expand Down
16 changes: 8 additions & 8 deletions src/shard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use std::{
use hashbrown::HashTable;

use crate::{
Equivalent, Lifecycle, MemoryUsed, Weighter,
linked_slab::{LinkedSlab, Token},
shim::sync::atomic::{self, AtomicU16},
Equivalent, Lifecycle, MemoryUsed, Weighter,
};

#[cfg(feature = "stats")]
Expand Down Expand Up @@ -281,13 +281,13 @@ impl<Key, Val, We, B, L, Plh> CacheShard<Key, Val, We, B, L, Plh> {
}

impl<
Key: Eq + Hash,
Val,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
Plh: SharedPlaceholder,
> CacheShard<Key, Val, We, B, L, Plh>
Key: Eq + Hash,
Val,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
Plh: SharedPlaceholder,
> CacheShard<Key, Val, We, B, L, Plh>
{
pub fn new(
hot_allocation: f64,
Expand Down
2 changes: 1 addition & 1 deletion src/shuttle_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
shim::{
sync::{self, atomic, Arc},
sync::{self, Arc, atomic},
thread,
},
sync::GuardResult,
Expand Down
17 changes: 8 additions & 9 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use std::{
};

use crate::{
DefaultHashBuilder, Equivalent, Lifecycle, MemoryUsed, UnitWeighter, Weighter,
linked_slab::Token,
options::{Options, OptionsBuilder},
shard::{CacheShard, InsertStrategy},
shim::rw_lock::RwLock,
sync_placeholder::SharedPlaceholder,
DefaultHashBuilder, Equivalent, Lifecycle, MemoryUsed, UnitWeighter, Weighter,
};

pub use crate::sync_placeholder::{GuardResult, JoinFuture, PlaceholderGuard};
Expand Down Expand Up @@ -73,12 +73,12 @@ impl<Key: Eq + Hash, Val: Clone, We: Weighter<Key, Val> + Clone> Cache<Key, Val,
}

impl<
Key: Eq + Hash,
Val: Clone,
We: Weighter<Key, Val> + Clone,
B: BuildHasher + Clone,
L: Lifecycle<Key, Val> + Clone,
> Cache<Key, Val, We, B, L>
Key: Eq + Hash,
Val: Clone,
We: Weighter<Key, Val> + Clone,
B: BuildHasher + Clone,
L: Lifecycle<Key, Val> + Clone,
> Cache<Key, Val, We, B, L>
{
/// Creates a new cache that can hold up to `weight_capacity` in weight.
/// `estimated_items_capacity` is the estimated number of items the cache is expected to hold,
Expand Down Expand Up @@ -271,8 +271,7 @@ impl<
Q: Hash + Equivalent<Key> + ?Sized,
{
let (shard, hash) = self.shard_for(key).unwrap();
let removed = shard.write().remove(hash, key);
removed
shard.write().remove(hash, key)
}

/// Inserts an item in the cache, but _only_ if an entry with key `key` already exists.
Expand Down
42 changes: 16 additions & 26 deletions src/sync_placeholder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ use std::{
};

use crate::{
Equivalent, Lifecycle, Weighter,
linked_slab::Token,
shard::CacheShard,
shim::{
OnceLock,
rw_lock::{RwLock, RwLockWriteGuard},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
},
thread, OnceLock,
thread,
},
Equivalent, Lifecycle, Weighter,
};

pub type SharedPlaceholder<Val> = Arc<Placeholder<Val>>;
Expand Down Expand Up @@ -204,14 +205,8 @@ impl<'a, Key, Val, We, B, L> PlaceholderGuard<'a, Key, Val, We, B, L> {
}
}

impl<
'a,
Key: Eq + Hash,
Val: Clone,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
> PlaceholderGuard<'a, Key, Val, We, B, L>
impl<'a, Key: Eq + Hash, Val: Clone, We: Weighter<Key, Val>, B: BuildHasher, L: Lifecycle<Key, Val>>
PlaceholderGuard<'a, Key, Val, We, B, L>
{
pub fn join<Q>(
lifecycle: &'a L,
Expand Down Expand Up @@ -314,13 +309,8 @@ impl<
}
}

impl<
Key: Eq + Hash,
Val: Clone,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
> PlaceholderGuard<'_, Key, Val, We, B, L>
impl<Key: Eq + Hash, Val: Clone, We: Weighter<Key, Val>, B: BuildHasher, L: Lifecycle<Key, Val>>
PlaceholderGuard<'_, Key, Val, We, B, L>
{
/// Inserts the value into the placeholder
///
Expand Down Expand Up @@ -490,14 +480,14 @@ impl<Q: ?Sized, Key, Val, We, B, L> Drop for JoinFuture<'_, '_, Q, Key, Val, We,
}

impl<
'a,
Key: Eq + Hash,
Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
Val: Clone,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
> Future for JoinFuture<'a, '_, Q, Key, Val, We, B, L>
'a,
Key: Eq + Hash,
Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
Val: Clone,
We: Weighter<Key, Val>,
B: BuildHasher,
L: Lifecycle<Key, Val>,
> Future for JoinFuture<'a, '_, Q, Key, Val, We, B, L>
{
type Output = Result<Val, PlaceholderGuard<'a, Key, Val, We, B, L>>;

Expand Down
2 changes: 1 addition & 1 deletion src/unsync.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
DefaultHashBuilder, Equivalent, Lifecycle, MemoryUsed, UnitWeighter, Weighter,
linked_slab::Token,
options::*,
shard::{self, CacheShard, InsertStrategy},
DefaultHashBuilder, Equivalent, Lifecycle, MemoryUsed, UnitWeighter, Weighter,
};
use std::hash::{BuildHasher, Hash};

Expand Down
14 changes: 14 additions & 0 deletions tools/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "memory_used_plot"
version = "0.1.0"
edition = "2024"
publish = false

[[bin]]
name = "memory_used_plot"
path = "src/memory_used_plot.rs"

[dependencies]
quick_cache = { path = ".." }
memory-stats = "1.2.0"
plotters = "0.3"
11 changes: 6 additions & 5 deletions examples/memory_used_plot.rs → tools/src/memory_used_plot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn main() {
println!("{:?}", memory_data);
memory_datas.push(memory_data);
}
let key: Key = (n as u128).to_le_bytes().into();
let key: Key = (n as u128).to_le_bytes();
cache.insert(key, ());
}

Expand All @@ -62,8 +62,9 @@ fn main() {
let mut chart = ChartBuilder::on(&root)
.caption(
format!(
"Memory Used ({})",
format!("{}(cap={})", type_name_of_val(&cache), cache_capacity)
"Memory Used ({}(cap={}))",
type_name_of_val(&cache),
cache_capacity
),
("sans-serif", 60),
)
Expand Down Expand Up @@ -104,8 +105,8 @@ fn main() {

chart
.configure_series_labels()
.background_style(&WHITE.mix(0.8))
.border_style(&BLACK)
.background_style(WHITE.mix(0.8))
.border_style(BLACK)
.label_font(("sans-serif", 20))
.legend_area_size(60)
.draw()
Expand Down
Loading