Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from triomphe::Arc to MiniArc, our own Arc implementation #456

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
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
3 changes: 3 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
13 changes: 7 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "moka"
version = "0.12.8"
version = "0.12.9"
edition = "2021"
# Rust 1.65 was released on Nov 3, 2022.
rust-version = "1.65"
Expand Down Expand Up @@ -50,11 +50,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 @@ -81,6 +76,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 @@ -92,6 +92,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 @@ -64,13 +64,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 @@ -101,11 +101,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 @@ -114,7 +114,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 @@ -177,33 +177,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 @@ -224,7 +224,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 @@ -278,7 +278,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 @@ -302,7 +302,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 @@ -312,7 +312,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 @@ -324,7 +324,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 @@ -337,7 +337,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 @@ -366,13 +366,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 @@ -384,15 +384,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
Loading