Skip to content

Commit

Permalink
Merge pull request #456 from moka-rs/mini-arc
Browse files Browse the repository at this point in the history
Switch from `triomphe::Arc` to `MiniArc`, our own `Arc` implementation
  • Loading branch information
tatsuya6502 authored Jan 1, 2025
2 parents c7b9456 + 9d78c2c commit f726592
Show file tree
Hide file tree
Showing 17 changed files with 542 additions and 151 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/Loom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI

on:
push:
paths-ignore:
- '.devcontainer/**'
- '.gitpod.yml'
- '.vscode/**'
- 'tests/**'
pull_request:
paths-ignore:
- '.devcontainer/**'
- '.gitpod.yml'
- '.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 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 --features 'future, sync' common::concurrent::arc::loom_tests
env:
RUSTFLAGS: '--cfg moka_loom'
8 changes: 8 additions & 0 deletions .github/workflows/Miri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ jobs:

- run: cargo miri setup

- name: Run Miri test on arc module using tree borrows
run: cargo miri test arc --features 'sync, future'
env:
MIRIFLAGS: '-Zmiri-tree-borrows'

- name: Run Miri test on deque module using tree borrows
run: cargo miri test deque --features 'sync, future'
env:
Expand All @@ -57,6 +62,9 @@ jobs:
env:
MIRIFLAGS: '-Zmiri-tree-borrows'

- name: Run Miri test on arc module using stacked borrows
run: cargo miri test arc --features 'sync, future'

- name: Run Miri test on deque module using stacked borrows
run: cargo miri test deque --features 'sync, future'

Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
"ENHANCEME",
"Eytan",
"getrandom",
"Goregaokar",
"hashbrown",
"Hasher",
"kani",
"Kawano",
"Manish",
"Manishearth",
"mapref",
"Miri",
"Moka",
Expand Down Expand Up @@ -66,6 +69,7 @@
"triomphe",
"trybuild",
"Uninit",
"unsize",
"unsync",
"Upsert",
"upserted",
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Bumped the minimum supported Rust version (MSRV) to 1.70 (June 1, 2023)

### Removed

- Removed `triomphe` crate from the dependency by adding our own internal `Arc` type.
([#456][gh-pull-0456])
- Our `Arc` is more memory efficient than `std::sync::Arc` or `triomphe::Arc` on
64-bit platforms as it uses a single `AtomicU32` counter.
- Removed needless traits along with `async-trait` usage. ([#445][gh-pull-0445], by
[@Swatinem][gh-Swatinem])

Expand Down Expand Up @@ -931,6 +935,7 @@ The minimum supported Rust version (MSRV) is now 1.51.0 (Mar 25, 2021).
[gh-pull-0474]: https://github.com/moka-rs/moka/pull/474/
[gh-pull-0466]: https://github.com/moka-rs/moka/pull/466/
[gh-pull-0460]: https://github.com/moka-rs/moka/pull/460/
[gh-pull-0456]: https://github.com/moka-rs/moka/pull/456/
[gh-pull-0452]: https://github.com/moka-rs/moka/pull/452/
[gh-pull-0445]: https://github.com/moka-rs/moka/pull/445/
[gh-pull-0444]: https://github.com/moka-rs/moka/pull/444/
Expand Down
11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ tagptr = "0.2"
thiserror = "1.0"
uuid = { version = "1.1", features = ["v4"] }

# Opt-out serde and stable_deref_trait features
# https://github.com/Manishearth/triomphe/pull/5
# 0.1.12 requires Rust 1.76
triomphe = { version = ">=0.1.3, <0.1.12", default-features = false }

# Optional dependencies (enabled by default)
quanta = { version = "0.12.2", optional = true }

Expand All @@ -80,6 +75,11 @@ paste = "1.0.9"
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls"] }
tokio = { version = "1.19", features = ["fs", "io-util", "macros", "rt-multi-thread", "sync", "time" ] }

# We cannot use `cfg(loom)` here because an indirect dependency `concurrent-queue`
# uses it.
[target.'cfg(moka_loom)'.dependencies]
loom = "0.7"

[target.'cfg(trybuild)'.dev-dependencies]
trybuild = "1.0"

Expand All @@ -91,6 +91,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [
"cfg(armv5te)",
"cfg(beta_clippy)",
"cfg(kani)",
"cfg(moka_loom)",
"cfg(mips)",
"cfg(rustver)",
"cfg(skip_large_mem_tests)",
Expand Down
52 changes: 26 additions & 26 deletions src/common/concurrent.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::common::{deque::DeqNode, time::Instant};
use crate::common::{concurrent::arc::MiniArc, deque::DeqNode, time::Instant};

use parking_lot::Mutex;
use std::{fmt, 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;
Expand Down Expand Up @@ -60,13 +60,13 @@ impl<K> Clone for KeyHash<K> {
}

pub(crate) struct KeyHashDate<K> {
entry_info: TrioArc<EntryInfo<K>>,
entry_info: MiniArc<EntryInfo<K>>,
}

impl<K> KeyHashDate<K> {
pub(crate) fn new(entry_info: &TrioArc<EntryInfo<K>>) -> Self {
pub(crate) fn new(entry_info: &MiniArc<EntryInfo<K>>) -> Self {
Self {
entry_info: TrioArc::clone(entry_info),
entry_info: MiniArc::clone(entry_info),
}
}

Expand Down Expand Up @@ -97,11 +97,11 @@ impl<K> KeyHashDate<K> {

pub(crate) struct KvEntry<K, V> {
pub(crate) key: Arc<K>,
pub(crate) entry: TrioArc<ValueEntry<K, V>>,
pub(crate) entry: MiniArc<ValueEntry<K, V>>,
}

impl<K, V> KvEntry<K, V> {
pub(crate) fn new(key: Arc<K>, entry: TrioArc<ValueEntry<K, V>>) -> Self {
pub(crate) fn new(key: Arc<K>, entry: MiniArc<ValueEntry<K, V>>) -> Self {
Self { key, entry }
}
}
Expand All @@ -110,7 +110,7 @@ impl<K, V> Clone for KvEntry<K, V> {
fn clone(&self) -> Self {
Self {
key: Arc::clone(&self.key),
entry: TrioArc::clone(&self.entry),
entry: MiniArc::clone(&self.entry),
}
}
}
Expand Down Expand Up @@ -173,33 +173,33 @@ impl<K> DeqNodes<K> {

pub(crate) struct ValueEntry<K, V> {
pub(crate) value: V,
info: TrioArc<EntryInfo<K>>,
nodes: TrioArc<Mutex<DeqNodes<K>>>,
info: MiniArc<EntryInfo<K>>,
nodes: MiniArc<Mutex<DeqNodes<K>>>,
}

impl<K, V> ValueEntry<K, V> {
pub(crate) fn new(value: V, entry_info: TrioArc<EntryInfo<K>>) -> Self {
pub(crate) fn new(value: V, entry_info: MiniArc<EntryInfo<K>>) -> Self {
#[cfg(feature = "unstable-debug-counters")]
self::debug_counters::InternalGlobalDebugCounters::value_entry_created();

Self {
value,
info: entry_info,
nodes: TrioArc::new(Mutex::new(DeqNodes::default())),
nodes: MiniArc::new(Mutex::new(DeqNodes::default())),
}
}

pub(crate) fn new_from(value: V, entry_info: TrioArc<EntryInfo<K>>, other: &Self) -> Self {
pub(crate) fn new_from(value: V, entry_info: MiniArc<EntryInfo<K>>, other: &Self) -> Self {
#[cfg(feature = "unstable-debug-counters")]
self::debug_counters::InternalGlobalDebugCounters::value_entry_created();
Self {
value,
info: entry_info,
nodes: TrioArc::clone(&other.nodes),
nodes: MiniArc::clone(&other.nodes),
}
}

pub(crate) fn entry_info(&self) -> &TrioArc<EntryInfo<K>> {
pub(crate) fn entry_info(&self) -> &MiniArc<EntryInfo<K>> {
&self.info
}

Expand All @@ -220,7 +220,7 @@ impl<K, V> ValueEntry<K, V> {
self.info.policy_weight()
}

pub(crate) fn deq_nodes(&self) -> &TrioArc<Mutex<DeqNodes<K>>> {
pub(crate) fn deq_nodes(&self) -> &MiniArc<Mutex<DeqNodes<K>>> {
&self.nodes
}

Expand Down Expand Up @@ -274,7 +274,7 @@ impl<K, V> Drop for ValueEntry<K, V> {
}
}

impl<K, V> AccessTime for TrioArc<ValueEntry<K, V>> {
impl<K, V> AccessTime for MiniArc<ValueEntry<K, V>> {
#[inline]
fn last_accessed(&self) -> Option<Instant> {
self.info.last_accessed()
Expand All @@ -298,7 +298,7 @@ impl<K, V> AccessTime for TrioArc<ValueEntry<K, V>> {

pub(crate) enum ReadOp<K, V> {
Hit {
value_entry: TrioArc<ValueEntry<K, V>>,
value_entry: MiniArc<ValueEntry<K, V>>,
is_expiry_modified: bool,
},
// u64 is the hash of the key.
Expand All @@ -308,7 +308,7 @@ pub(crate) enum ReadOp<K, V> {
pub(crate) enum WriteOp<K, V> {
Upsert {
key_hash: KeyHash<K>,
value_entry: TrioArc<ValueEntry<K, V>>,
value_entry: MiniArc<ValueEntry<K, V>>,
/// Entry generation after the operation.
entry_gen: u16,
old_weight: u32,
Expand All @@ -320,7 +320,7 @@ pub(crate) enum WriteOp<K, V> {
},
}

/// Cloning a `WriteOp` is safe and cheap because it uses `Arc` and `TrioArc` pointers to
/// Cloning a `WriteOp` is safe and cheap because it uses `Arc` and `MiniArc` pointers to
/// the actual data.
impl<K, V> Clone for WriteOp<K, V> {
fn clone(&self) -> Self {
Expand All @@ -333,7 +333,7 @@ impl<K, V> Clone for WriteOp<K, V> {
new_weight,
} => Self::Upsert {
key_hash: key_hash.clone(),
value_entry: TrioArc::clone(value_entry),
value_entry: MiniArc::clone(value_entry),
entry_gen: *entry_gen,
old_weight: *old_weight,
new_weight: *new_weight,
Expand Down Expand Up @@ -362,13 +362,13 @@ impl<K, V> WriteOp<K, V> {
pub(crate) fn new_upsert(
key: &Arc<K>,
hash: u64,
value_entry: &TrioArc<ValueEntry<K, V>>,
value_entry: &MiniArc<ValueEntry<K, V>>,
entry_generation: u16,
old_weight: u32,
new_weight: u32,
) -> Self {
let key_hash = KeyHash::new(Arc::clone(key), hash);
let value_entry = TrioArc::clone(value_entry);
let value_entry = MiniArc::clone(value_entry);
Self::Upsert {
key_hash,
value_entry,
Expand All @@ -380,15 +380,15 @@ impl<K, V> WriteOp<K, V> {
}

pub(crate) struct OldEntryInfo<K, V> {
pub(crate) entry: TrioArc<ValueEntry<K, V>>,
pub(crate) entry: MiniArc<ValueEntry<K, V>>,
pub(crate) last_accessed: Option<Instant>,
pub(crate) last_modified: Option<Instant>,
}

impl<K, V> OldEntryInfo<K, V> {
pub(crate) fn new(entry: &TrioArc<ValueEntry<K, V>>) -> Self {
pub(crate) fn new(entry: &MiniArc<ValueEntry<K, V>>) -> Self {
Self {
entry: TrioArc::clone(entry),
entry: MiniArc::clone(entry),
last_accessed: entry.last_accessed(),
last_modified: entry.last_modified(),
}
Expand Down
Loading

0 comments on commit f726592

Please sign in to comment.