diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1a9123..c92f86b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/.gitignore b/.gitignore index 8178a02..02d2a65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/target -/Cargo.lock -cache_memory_used.png \ No newline at end of file +**/target +**/Cargo.lock +**/cache_memory_used.png diff --git a/Cargo.toml b/Cargo.toml index 66e3d88..2757071 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 "] @@ -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"] @@ -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" diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs index 7c4f1b2..e33de2c 100644 --- a/benches/benchmarks.rs +++ b/benches/benchmarks.rs @@ -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; diff --git a/benches/placeholder_async_bench.rs b/benches/placeholder_async_bench.rs index 5c63890..06aeb6e 100644 --- a/benches/placeholder_async_bench.rs +++ b/benches/placeholder_async_bench.rs @@ -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) { diff --git a/benches/placeholder_bench.rs b/benches/placeholder_bench.rs index 5f6a53a..78610aa 100644 --- a/benches/placeholder_bench.rs +++ b/benches/placeholder_bench.rs @@ -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) { diff --git a/examples/custom_weight.rs b/examples/custom_weight.rs index f3b07b1..70c099a 100644 --- a/examples/custom_weight.rs +++ b/examples/custom_weight.rs @@ -1,4 +1,4 @@ -use quick_cache::{sync::Cache, Weighter}; +use quick_cache::{Weighter, sync::Cache}; #[derive(Clone)] struct StringWeighter; diff --git a/examples/equivalent.rs b/examples/equivalent.rs index 296e5d5..2c85072 100644 --- a/examples/equivalent.rs +++ b/examples/equivalent.rs @@ -1,4 +1,4 @@ -use quick_cache::{sync::Cache, Equivalent}; +use quick_cache::{Equivalent, sync::Cache}; #[derive(Debug, Hash)] pub struct Pair(pub A, pub B); diff --git a/examples/eviction_listener.rs b/examples/eviction_listener.rs index 4861993..5a1b91d 100644 --- a/examples/eviction_listener.rs +++ b/examples/eviction_listener.rs @@ -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)] diff --git a/src/lib.rs b/src/lib.rs index e0e67cb..0607915 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -210,7 +210,7 @@ impl MemoryUsed { mod tests { use std::{ hash::Hash, - sync::{atomic::AtomicUsize, Arc}, + sync::{Arc, atomic::AtomicUsize}, time::Duration, }; @@ -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(()))); }); @@ -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(()))); diff --git a/src/linked_slab.rs b/src/linked_slab.rs index 97ced29..bd840da 100644 --- a/src/linked_slab.rs +++ b/src/linked_slab.rs @@ -107,17 +107,21 @@ impl LinkedSlab { /// 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, diff --git a/src/shard.rs b/src/shard.rs index 52a2546..c252827 100644 --- a/src/shard.rs +++ b/src/shard.rs @@ -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")] @@ -281,13 +281,13 @@ impl CacheShard { } impl< - Key: Eq + Hash, - Val, - We: Weighter, - B: BuildHasher, - L: Lifecycle, - Plh: SharedPlaceholder, - > CacheShard + Key: Eq + Hash, + Val, + We: Weighter, + B: BuildHasher, + L: Lifecycle, + Plh: SharedPlaceholder, +> CacheShard { pub fn new( hot_allocation: f64, diff --git a/src/shuttle_tests.rs b/src/shuttle_tests.rs index 427b317..9ae6668 100644 --- a/src/shuttle_tests.rs +++ b/src/shuttle_tests.rs @@ -1,6 +1,6 @@ use crate::{ shim::{ - sync::{self, atomic, Arc}, + sync::{self, Arc, atomic}, thread, }, sync::GuardResult, diff --git a/src/sync.rs b/src/sync.rs index 667cdaa..dc6139c 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -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}; @@ -73,12 +73,12 @@ impl + Clone> Cache + Clone, - B: BuildHasher + Clone, - L: Lifecycle + Clone, - > Cache + Key: Eq + Hash, + Val: Clone, + We: Weighter + Clone, + B: BuildHasher + Clone, + L: Lifecycle + Clone, +> Cache { /// 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, @@ -271,8 +271,7 @@ impl< Q: Hash + Equivalent + ?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. diff --git a/src/sync_placeholder.rs b/src/sync_placeholder.rs index de1c162..0c5d04c 100644 --- a/src/sync_placeholder.rs +++ b/src/sync_placeholder.rs @@ -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 = Arc>; @@ -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, - B: BuildHasher, - L: Lifecycle, - > PlaceholderGuard<'a, Key, Val, We, B, L> +impl<'a, Key: Eq + Hash, Val: Clone, We: Weighter, B: BuildHasher, L: Lifecycle> + PlaceholderGuard<'a, Key, Val, We, B, L> { pub fn join( lifecycle: &'a L, @@ -314,13 +309,8 @@ impl< } } -impl< - Key: Eq + Hash, - Val: Clone, - We: Weighter, - B: BuildHasher, - L: Lifecycle, - > PlaceholderGuard<'_, Key, Val, We, B, L> +impl, B: BuildHasher, L: Lifecycle> + PlaceholderGuard<'_, Key, Val, We, B, L> { /// Inserts the value into the placeholder /// @@ -490,14 +480,14 @@ impl Drop for JoinFuture<'_, '_, Q, Key, Val, We, } impl< - 'a, - Key: Eq + Hash, - Q: Hash + Equivalent + ToOwned + ?Sized, - Val: Clone, - We: Weighter, - B: BuildHasher, - L: Lifecycle, - > Future for JoinFuture<'a, '_, Q, Key, Val, We, B, L> + 'a, + Key: Eq + Hash, + Q: Hash + Equivalent + ToOwned + ?Sized, + Val: Clone, + We: Weighter, + B: BuildHasher, + L: Lifecycle, +> Future for JoinFuture<'a, '_, Q, Key, Val, We, B, L> { type Output = Result>; diff --git a/src/unsync.rs b/src/unsync.rs index bec78f1..302274d 100644 --- a/src/unsync.rs +++ b/src/unsync.rs @@ -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}; diff --git a/tools/Cargo.toml b/tools/Cargo.toml new file mode 100644 index 0000000..e6420ed --- /dev/null +++ b/tools/Cargo.toml @@ -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" diff --git a/examples/memory_used_plot.rs b/tools/src/memory_used_plot.rs similarity index 93% rename from examples/memory_used_plot.rs rename to tools/src/memory_used_plot.rs index c8c6e6e..f5be995 100644 --- a/examples/memory_used_plot.rs +++ b/tools/src/memory_used_plot.rs @@ -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, ()); } @@ -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), ) @@ -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()