From 2b08fff28e63d76edd68985a4fa32568a9d8af75 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Sat, 11 Jan 2025 22:33:27 +0800 Subject: [PATCH] Replace `triomphe::Arc` with our own `MiniArc` type --- .github/workflows/Loom.yml | 48 +++++ Cargo.toml | 12 +- README.md | 3 - src/common/concurrent.rs | 35 ++-- src/common/concurrent/arc.rs | 331 ++++++++++++++++++++++++++++++++ src/common/concurrent/deques.rs | 21 +- src/sync/base_cache.rs | 34 ++-- src/sync/iter.rs | 5 +- src/sync/mapref.rs | 5 +- 9 files changed, 433 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/Loom.yml create mode 100644 src/common/concurrent/arc.rs diff --git a/.github/workflows/Loom.yml b/.github/workflows/Loom.yml new file mode 100644 index 0000000..6eaa49d --- /dev/null +++ b/.github/workflows/Loom.yml @@ -0,0 +1,48 @@ +name: Loom + +on: + push: + paths-ignore: + - '.devcontainer/**' + - '.vscode/**' + - 'tests/**' + pull_request: + paths-ignore: + - '.devcontainer/**' + - '.vscode/**' + - 'tests/**' + schedule: + # Run against the last commit on the default branch on Friday at 8pm (UTC?) + - cron: '0 20 * * 5' + +jobs: + pre_job: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + # https://github.com/marketplace/actions/skip-duplicate-actions + uses: fkirc/skip-duplicate-actions@v5 + with: + concurrent_skipping: 'same_content' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + test: + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' + runs-on: ubuntu-latest + + steps: + - name: Checkout Mini Moka + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - name: Run tests in concurrent::arc module + run: cargo test --release --lib common::concurrent::arc::loom_tests + env: + RUSTFLAGS: '--cfg moka_loom' diff --git a/Cargo.toml b/Cargo.toml index 29a4604..df1ae89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,10 +25,6 @@ crossbeam-utils = "0.8" smallvec = "1.8" tagptr = "0.2" -# Opt-out serde and stable_deref_trait features -# https://github.com/Manishearth/triomphe/pull/5 -triomphe = { version = "0.1.13", default-features = false } - # Optional dependencies (enabled by default) dashmap = { version = "6.1", optional = true } @@ -46,11 +42,15 @@ trybuild = "1.0" features = [] rustdoc-args = ["--cfg", "docsrs"] +[target.'cfg(moka_loom)'.dependencies] +loom = "0.7" + [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ + "cfg(beta_clippy)", + "cfg(circleci)", "cfg(kani)", + "cfg(moka_loom)", "cfg(skeptic)", - "cfg(circleci)", "cfg(trybuild)", - "cfg(beta_clippy)", ] } diff --git a/README.md b/README.md index 2175fa6..b57e2b4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ [![dependency status][deps-rs-badge]][deps-rs] [![license][license-badge]](#license) - Mini Moka is a fast, concurrent cache library for Rust. Mini Moka is a light edition of [Moka][moka-git]. @@ -24,14 +23,12 @@ algorithm to determine which entries to evict when the capacity is exceeded. [deps-rs-badge]: https://deps.rs/repo/github/moka-rs/mini-moka/status.svg [license-badge]: https://img.shields.io/crates/l/mini-moka.svg - [gh-actions]: https://github.com/moka-rs/mini-moka/actions?query=workflow%3ACI [crate]: https://crates.io/crates/mini-moka [docs]: https://docs.rs/mini-moka [deps-rs]: https://deps.rs/repo/github/moka-rs/mini-moka - [moka-git]: https://github.com/moka-rs/moka [caffeine-git]: https://github.com/ben-manes/caffeine diff --git a/src/common/concurrent.rs b/src/common/concurrent.rs index 239e0b6..1f388e1 100644 --- a/src/common/concurrent.rs +++ b/src/common/concurrent.rs @@ -1,9 +1,7 @@ -use crate::common::{deque::DeqNode, time::Instant}; - use std::{ptr::NonNull, sync::Arc}; use tagptr::TagNonNull; -use triomphe::Arc as TrioArc; +pub(crate) mod arc; pub(crate) mod constants; pub(crate) mod deques; pub(crate) mod entry_info; @@ -11,7 +9,8 @@ pub(crate) mod housekeeper; pub(crate) mod atomic_time; -use self::entry_info::EntryInfo; +use self::{arc::MiniArc, entry_info::EntryInfo}; +use crate::common::{deque::DeqNode, time::Instant}; pub(crate) type Weigher = Arc u32 + Send + Sync + 'static>; @@ -44,14 +43,14 @@ impl Clone for KeyHash { pub(crate) struct KeyDate { key: Arc, - entry_info: TrioArc>, + entry_info: MiniArc>, } impl KeyDate { - pub(crate) fn new(key: Arc, entry_info: &TrioArc>) -> Self { + pub(crate) fn new(key: Arc, entry_info: &MiniArc>) -> Self { Self { key, - entry_info: TrioArc::clone(entry_info), + entry_info: MiniArc::clone(entry_info), } } @@ -63,15 +62,15 @@ impl KeyDate { pub(crate) struct KeyHashDate { key: Arc, hash: u64, - entry_info: TrioArc>, + entry_info: MiniArc>, } impl KeyHashDate { - pub(crate) fn new(kh: KeyHash, entry_info: &TrioArc>) -> Self { + pub(crate) fn new(kh: KeyHash, entry_info: &MiniArc>) -> Self { Self { key: kh.key, hash: kh.hash, - entry_info: TrioArc::clone(entry_info), + entry_info: MiniArc::clone(entry_info), } } @@ -90,11 +89,11 @@ impl KeyHashDate { pub(crate) struct KvEntry { pub(crate) key: Arc, - pub(crate) entry: TrioArc>, + pub(crate) entry: MiniArc>, } impl KvEntry { - pub(crate) fn new(key: Arc, entry: TrioArc>) -> Self { + pub(crate) fn new(key: Arc, entry: MiniArc>) -> Self { Self { key, entry } } } @@ -151,18 +150,18 @@ pub(crate) type KeyDeqNodeWo = NonNull>>; pub(crate) struct ValueEntry { pub(crate) value: V, - info: TrioArc>, + info: MiniArc>, } impl ValueEntry { - pub(crate) fn new(value: V, entry_info: TrioArc>) -> Self { + pub(crate) fn new(value: V, entry_info: MiniArc>) -> Self { Self { value, info: entry_info, } } - pub(crate) fn entry_info(&self) -> &TrioArc> { + pub(crate) fn entry_info(&self) -> &MiniArc> { &self.info } @@ -216,7 +215,7 @@ impl ValueEntry { } } -impl AccessTime for TrioArc> { +impl AccessTime for MiniArc> { #[inline] fn last_accessed(&self) -> Option { self.info.last_accessed() @@ -240,14 +239,14 @@ impl AccessTime for TrioArc> { pub(crate) enum ReadOp { // u64 is the hash of the key. - Hit(u64, TrioArc>, Instant), + Hit(u64, MiniArc>, Instant), Miss(u64), } pub(crate) enum WriteOp { Upsert { key_hash: KeyHash, - value_entry: TrioArc>, + value_entry: MiniArc>, old_weight: u32, new_weight: u32, }, diff --git a/src/common/concurrent/arc.rs b/src/common/concurrent/arc.rs new file mode 100644 index 0000000..c2d8d19 --- /dev/null +++ b/src/common/concurrent/arc.rs @@ -0,0 +1,331 @@ +// This module's source code was written by us, the `moka` developers, referring to +// the following book and code: +// +// - Chapter 6. Building Our Own "Arc" of the Rust Atomics and Locks book. +// - Rust Atomics and Locks by Mara Bos (O’Reilly). Copyright 2023 Mara Bos, +// ISBN: 978-1-098-11944-7 +// - https://marabos.nl/atomics/ +// - The `triomphe` crate v0.1.13 and v0.1.11 by Manish Goregaokar (Manishearth) +// - MIT or Apache-2.0 License +// - https://github.com/Manishearth/triomphe +// - `std::sync::Arc` in the Rust Standard Library (1.81.0). +// - MIT or Apache-2.0 License + +use std::{ + fmt, + hash::{Hash, Hasher}, + ops::Deref, + ptr::NonNull, +}; + +#[cfg(not(moka_loom))] +use std::sync::atomic::{self, AtomicU32}; + +#[cfg(moka_loom)] +use loom::sync::atomic::{self, AtomicU32}; + +/// A thread-safe reference-counting pointer. `MiniArc` is similar to +/// `std::sync::Arc`, Atomically Reference Counted shared pointer, but with a few +/// differences: +/// +/// - Smaller memory overhead: +/// - `MiniArc` does not support weak references, so it does not need to store a +/// weak reference count. +/// - `MiniArc` uses `AtomicU32` for the reference count, while `std::sync::Arc` +/// uses `AtomicUsize`. On a 64-bit system, `AtomicU32` is half the size of +/// `AtomicUsize`. +/// - Note: Depending on the value type `T`, the Rust compiler may add +/// padding to the internal struct of `MiniArc`, so the actual memory +/// overhead may vary. +/// - Smaller code size: +/// - Only about 100 lines of code. +/// - This is because `MiniArc` provides only the methods needed for the +/// `moka` and `mini-moka` crates. +/// - Smaller code size means less chance of bugs. +pub(crate) struct MiniArc { + ptr: NonNull>, +} + +struct ArcData { + ref_count: AtomicU32, + data: T, +} + +/// A soft limit on the amount of references that may be made to an `MiniArc`. +/// +/// Going above this limit will abort your program (although not necessarily) +/// at _exactly_ `MAX_REFCOUNT + 1` references. +const MAX_REFCOUNT: u32 = (i32::MAX) as u32; + +unsafe impl Send for MiniArc {} +unsafe impl Sync for MiniArc {} + +impl MiniArc { + pub(crate) fn new(data: T) -> MiniArc { + MiniArc { + ptr: NonNull::from(Box::leak(Box::new(ArcData { + ref_count: AtomicU32::new(1), + data, + }))), + } + } +} + +impl MiniArc { + /// Gets the number of [`MiniArc`] pointers to this allocation + #[cfg(test)] + pub(crate) fn count(this: &Self) -> u32 { + use atomic::Ordering::Acquire; + + this.data().ref_count.load(Acquire) + } + + /// Returns `true` if the two `MiniArc`s point to the same allocation in a + /// vein similar to [`ptr::eq`]. + /// + /// # Safety + /// + /// This function is unreliable when `T` is a `dyn Trait`. Currently + /// coercing `MiniArc` to `MiniArc` is not possible, so + /// this is not a problem in practice. However, if this coercion becomes + /// possible in the future, this function may return incorrect results when + /// comparing `MiniArc` instances. + /// + /// To fix this, we must rise the minimum supported Rust version (MSRV) to + /// 1.76 and use `std::ptr::addr_eq` internally instead of `eq` (`==`). + /// `addr_eq` compares the _addresses_ of the pointers for equality, + /// ignoring any metadata in fat pointers. + /// + /// See the following `triomphe` issue for more information: + /// https://github.com/Manishearth/triomphe/pull/84 + /// + /// Note that `triomphe` has a feature called `unsize`, which enables the + /// coercion by using the `unsize` crate. `MiniArc` does not have such a + /// feature, so we are safe for now. + #[inline] + #[allow(ambiguous_wide_pointer_comparisons)] // Remove when MSRV is 1.76 or newer. + pub(crate) fn ptr_eq(this: &Self, other: &Self) -> bool { + // `addr_eq` requires Rust 1.76 or newer. + // ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) + this.ptr.as_ptr() == other.ptr.as_ptr() + } + + #[inline] + fn data(&self) -> &ArcData { + unsafe { self.ptr.as_ref() } + } +} + +impl Deref for MiniArc { + type Target = T; + + fn deref(&self) -> &T { + &self.data().data + } +} + +impl Clone for MiniArc { + fn clone(&self) -> Self { + use atomic::Ordering::Relaxed; + + if self.data().ref_count.fetch_add(1, Relaxed) > MAX_REFCOUNT { + std::process::abort(); + } + + MiniArc { ptr: self.ptr } + } +} + +impl Drop for MiniArc { + fn drop(&mut self) { + use std::sync::atomic::Ordering::{Acquire, Release}; + + if self.data().ref_count.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + unsafe { + drop(Box::from_raw(self.ptr.as_ptr())); + } + } + } +} + +impl Default for MiniArc { + /// Creates a new `MiniArc`, with the `Default` value for `T`. + fn default() -> MiniArc { + MiniArc::new(Default::default()) + } +} + +impl PartialEq for MiniArc { + fn eq(&self, other: &MiniArc) -> bool { + // TODO: pointer equality is incorrect if `T` is not `Eq`. + // See: https://github.com/Manishearth/triomphe/pull/88 + Self::ptr_eq(self, other) || *(*self) == *(*other) + } + + #[allow(clippy::partialeq_ne_impl)] + fn ne(&self, other: &MiniArc) -> bool { + !Self::ptr_eq(self, other) && *(*self) != *(*other) + } +} + +impl Eq for MiniArc {} + +impl fmt::Display for MiniArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl fmt::Debug for MiniArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl fmt::Pointer for MiniArc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.ptr.as_ptr(), f) + } +} + +impl Hash for MiniArc { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + +#[cfg(all(test, not(moka_loom)))] +mod tests { + use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + + use super::*; + + #[test] + fn test_drop() { + static NUM_DROPS: AtomicUsize = AtomicUsize::new(0); + + struct DetectDrop; + + impl Drop for DetectDrop { + fn drop(&mut self) { + NUM_DROPS.fetch_add(1, Relaxed); + } + } + + // Create two MiniArcs sharing an object containing a string + // and a DetectDrop, to detect when it is dropped. + let x = MiniArc::new(("hello", DetectDrop)); + let y = x.clone(); + + // Send x to another thread, and use it there. + let t = std::thread::spawn(move || { + assert_eq!(x.0, "hello"); + }); + + // In parallel, y should still be usable here. + assert_eq!(y.0, "hello"); + assert!(MiniArc::count(&y) >= 1); + + // Wait for the thread to finish. + t.join().unwrap(); + + // One MiniArc, x, should be dropped by now. + // We still have y, so the object should not have been dropped yet. + assert_eq!(NUM_DROPS.load(Relaxed), 0); + assert_eq!(MiniArc::count(&y), 1); + + // Drop the remaining `MiniArc`. + drop(y); + + // Now that `y` is dropped too, + // the object should have been dropped. + assert_eq!(NUM_DROPS.load(Relaxed), 1); + } + + #[test] + fn test_eq() { + let w = MiniArc::new(6502); + let x = w.clone(); + let y = MiniArc::new(6502); + let z = MiniArc::new(8086); + + assert_eq!(w, x); + assert_eq!(x, w); + assert_eq!(w, y); + assert_eq!(y, w); + assert_ne!(y, z); + assert_ne!(z, y); + } + + #[test] + fn test_partial_eq_bug() { + let float = f32::NAN; + assert_ne!(float, float); + let arc = MiniArc::new(f32::NAN); + // TODO: this is a bug. + // See: https://github.com/Manishearth/triomphe/pull/88 + assert_eq!(arc, arc); + } + + #[allow(dead_code)] + const fn is_partial_eq() {} + + #[allow(dead_code)] + const fn is_eq() {} + + // compile-time check that PartialEq/Eq is correctly derived + const _: () = is_partial_eq::>(); + const _: () = is_eq::>(); +} + +#[cfg(all(test, moka_loom))] +mod loom_tests { + use super::*; + + #[test] + fn test_drop() { + use loom::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + + struct DetectDrop(loom::sync::Arc); + + impl Drop for DetectDrop { + fn drop(&mut self) { + self.0.fetch_add(1, Relaxed); + } + } + + loom::model(move || { + let num_drops = loom::sync::Arc::new(AtomicUsize::new(0)); + + // Create two MiniArcs sharing an object containing a string + // and a DetectDrop, to detect when it is dropped. + let x = MiniArc::new(("hello", DetectDrop(loom::sync::Arc::clone(&num_drops)))); + let y = x.clone(); + + // Send x to another thread, and use it there. + let t = loom::thread::spawn(move || { + assert_eq!(x.0, "hello"); + }); + + // In parallel, y should still be usable here. + assert_eq!(y.0, "hello"); + assert!(MiniArc::count(&y) >= 1); + + // Wait for the thread to finish. + t.join().unwrap(); + + // One MiniArc, x, should be dropped by now. + // We still have y, so the object should not have been dropped yet. + assert_eq!(num_drops.load(Relaxed), 0); + assert_eq!(MiniArc::count(&y), 1); + + // Drop the remaining `MiniArc`. + drop(y); + + // Now that `y` is dropped too, + // the object should have been dropped. + assert_eq!(num_drops.load(Relaxed), 1); + }); + } +} diff --git a/src/common/concurrent/deques.rs b/src/common/concurrent/deques.rs index c7eed6c..4880a4d 100644 --- a/src/common/concurrent/deques.rs +++ b/src/common/concurrent/deques.rs @@ -1,4 +1,4 @@ -use super::{KeyDate, KeyHashDate, ValueEntry}; +use super::{arc::MiniArc, KeyDate, KeyHashDate, ValueEntry}; use crate::common::{ deque::{DeqNode, Deque}, CacheRegion, @@ -6,7 +6,6 @@ use crate::common::{ use std::ptr::NonNull; use tagptr::TagNonNull; -use triomphe::Arc as TrioArc; pub(crate) struct Deques { pub(crate) window: Deque>, // Not used yet. pub(crate) probation: Deque>, @@ -30,7 +29,7 @@ impl Deques { &mut self, region: CacheRegion, khd: KeyHashDate, - entry: &TrioArc>, + entry: &MiniArc>, ) { let node = Box::new(DeqNode::new(khd)); let node = match region { @@ -43,13 +42,13 @@ impl Deques { entry.set_access_order_q_node(Some(tagged_node)); } - pub(crate) fn push_back_wo(&mut self, kd: KeyDate, entry: &TrioArc>) { + pub(crate) fn push_back_wo(&mut self, kd: KeyDate, entry: &MiniArc>) { let node = Box::new(DeqNode::new(kd)); let node = self.write_order.push_back(node); entry.set_write_order_q_node(Some(node)); } - pub(crate) fn move_to_back_ao(&mut self, entry: &TrioArc>) { + pub(crate) fn move_to_back_ao(&mut self, entry: &MiniArc>) { if let Some(tagged_node) = entry.access_order_q_node() { let (node, tag) = tagged_node.decompose(); let p = unsafe { node.as_ref() }; @@ -71,7 +70,7 @@ impl Deques { pub(crate) fn move_to_back_ao_in_deque( deq_name: &str, deq: &mut Deque>, - entry: &TrioArc>, + entry: &MiniArc>, ) { if let Some(tagged_node) = entry.access_order_q_node() { let (node, tag) = tagged_node.decompose(); @@ -89,7 +88,7 @@ impl Deques { } } - pub(crate) fn move_to_back_wo(&mut self, entry: &TrioArc>) { + pub(crate) fn move_to_back_wo(&mut self, entry: &MiniArc>) { if let Some(node) = entry.write_order_q_node() { let p = unsafe { node.as_ref() }; if self.write_order.contains(p) { @@ -100,7 +99,7 @@ impl Deques { pub(crate) fn move_to_back_wo_in_deque( deq: &mut Deque>, - entry: &TrioArc>, + entry: &MiniArc>, ) { if let Some(node) = entry.write_order_q_node() { let p = unsafe { node.as_ref() }; @@ -110,7 +109,7 @@ impl Deques { } } - pub(crate) fn unlink_ao(&mut self, entry: &TrioArc>) { + pub(crate) fn unlink_ao(&mut self, entry: &MiniArc>) { if let Some(node) = entry.take_access_order_q_node() { self.unlink_node_ao(node); } @@ -119,14 +118,14 @@ impl Deques { pub(crate) fn unlink_ao_from_deque( deq_name: &str, deq: &mut Deque>, - entry: &TrioArc>, + entry: &MiniArc>, ) { if let Some(node) = entry.take_access_order_q_node() { unsafe { Self::unlink_node_ao_from_deque(deq_name, deq, node) }; } } - pub(crate) fn unlink_wo(deq: &mut Deque>, entry: &TrioArc>) { + pub(crate) fn unlink_wo(deq: &mut Deque>, entry: &MiniArc>) { if let Some(node) = entry.take_write_order_q_node() { Self::unlink_node_wo(deq, node); } diff --git a/src/sync/base_cache.rs b/src/sync/base_cache.rs index 84e8bf4..c486125 100644 --- a/src/sync/base_cache.rs +++ b/src/sync/base_cache.rs @@ -3,6 +3,7 @@ use crate::{ common::{ self, concurrent::{ + arc::MiniArc, atomic_time::AtomicInstant, constants::{ READ_LOG_FLUSH_POINT, READ_LOG_SIZE, WRITE_LOG_FLUSH_POINT, WRITE_LOG_SIZE, @@ -36,7 +37,6 @@ use std::{ }, time::Duration, }; -use triomphe::Arc as TrioArc; pub(crate) struct BaseCache { pub(crate) inner: Arc>, @@ -178,7 +178,7 @@ where } else { // Valid entry. let v = arc_entry.value.clone(); - let e = TrioArc::clone(arc_entry); + let e = MiniArc::clone(arc_entry); // Drop the entry to avoid to deadlock with record_read_op. std::mem::drop(entry); record(ReadOp::Hit(hash, e, now), now); @@ -235,7 +235,7 @@ where } impl BaseCache { - pub(crate) fn is_expired_entry(&self, entry: &TrioArc>) -> bool { + pub(crate) fn is_expired_entry(&self, entry: &MiniArc>) -> bool { let i = &self.inner; let (ttl, tti, va) = (&i.time_to_live(), &i.time_to_idle(), &i.valid_after()); let now = i.current_time_from_expiration_clock(); @@ -295,7 +295,7 @@ where *entry = self.new_value_entry_from(value.clone(), ts, weight, entry); update_op = Some(WriteOp::Upsert { key_hash: KeyHash::new(Arc::clone(&key), hash), - value_entry: TrioArc::clone(entry), + value_entry: MiniArc::clone(entry), old_weight, new_weight: weight, }); @@ -305,7 +305,7 @@ where let entry = self.new_value_entry(value.clone(), ts, weight); insert_op = Some(WriteOp::Upsert { key_hash: KeyHash::new(Arc::clone(&key), hash), - value_entry: TrioArc::clone(&entry), + value_entry: MiniArc::clone(&entry), old_weight: 0, new_weight: weight, }); @@ -325,9 +325,9 @@ where value: V, timestamp: Instant, policy_weight: u32, - ) -> TrioArc> { - let info = TrioArc::new(EntryInfo::new(timestamp, policy_weight)); - TrioArc::new(ValueEntry::new(value, info)) + ) -> MiniArc> { + let info = MiniArc::new(EntryInfo::new(timestamp, policy_weight)); + MiniArc::new(ValueEntry::new(value, info)) } #[inline] @@ -337,15 +337,15 @@ where timestamp: Instant, policy_weight: u32, other: &ValueEntry, - ) -> TrioArc> { - let info = TrioArc::clone(other.entry_info()); + ) -> MiniArc> { + let info = MiniArc::clone(other.entry_info()); // To prevent this updated ValueEntry from being evicted by an expiration policy, // set the dirty flag to true. It will be reset to false when the write is applied. info.set_dirty(true); info.set_last_accessed(timestamp); info.set_last_modified(timestamp); info.set_policy_weight(policy_weight); - TrioArc::new(ValueEntry::new(value, info)) + MiniArc::new(ValueEntry::new(value, info)) } #[inline] @@ -452,9 +452,9 @@ enum AdmissionResult { }, } -type CacheStore = dashmap::DashMap, TrioArc>, S>; +type CacheStore = dashmap::DashMap, MiniArc>, S>; -type CacheEntryRef<'a, K, V> = DashMapRef<'a, Arc, TrioArc>>; +type CacheEntryRef<'a, K, V> = DashMapRef<'a, Arc, MiniArc>>; pub(crate) struct Inner { max_capacity: Option, @@ -816,7 +816,7 @@ where fn handle_upsert( &self, kh: KeyHash, - entry: TrioArc>, + entry: MiniArc>, old_weight: u32, new_weight: u32, deqs: &mut Deques, @@ -974,7 +974,7 @@ where fn handle_admit( &self, kh: KeyHash, - entry: &TrioArc>, + entry: &MiniArc>, policy_weight: u32, deqs: &mut Deques, counters: &mut EvictionCounters, @@ -994,7 +994,7 @@ where fn handle_remove( deqs: &mut Deques, - entry: TrioArc>, + entry: MiniArc>, counters: &mut EvictionCounters, ) { if entry.is_admitted() { @@ -1012,7 +1012,7 @@ where ao_deq_name: &str, ao_deq: &mut Deque>, wo_deq: &mut Deque>, - entry: TrioArc>, + entry: MiniArc>, counters: &mut EvictionCounters, ) { if entry.is_admitted() { diff --git a/src/sync/iter.rs b/src/sync/iter.rs index 9809819..366aeaf 100644 --- a/src/sync/iter.rs +++ b/src/sync/iter.rs @@ -1,14 +1,13 @@ use super::{base_cache::BaseCache, mapref::EntryRef}; -use crate::common::concurrent::ValueEntry; +use crate::common::concurrent::{arc::MiniArc, ValueEntry}; use std::{ hash::{BuildHasher, Hash}, sync::Arc, }; -use triomphe::Arc as TrioArc; pub(crate) type DashMapIter<'a, K, V, S> = - dashmap::iter::Iter<'a, Arc, TrioArc>, S>; + dashmap::iter::Iter<'a, Arc, MiniArc>, S>; pub struct Iter<'a, K, V, S> { cache: &'a BaseCache, diff --git a/src/sync/mapref.rs b/src/sync/mapref.rs index c59c13f..5c2cded 100644 --- a/src/sync/mapref.rs +++ b/src/sync/mapref.rs @@ -1,10 +1,9 @@ -use crate::common::concurrent::ValueEntry; +use crate::common::concurrent::{arc::MiniArc, ValueEntry}; use std::{hash::Hash, sync::Arc}; -use triomphe::Arc as TrioArc; type DashMapRef<'a, K, V> = - dashmap::mapref::multiple::RefMulti<'a, Arc, TrioArc>>; + dashmap::mapref::multiple::RefMulti<'a, Arc, MiniArc>>; pub struct EntryRef<'a, K, V>(DashMapRef<'a, K, V>);