From 74d1cb5fa749f50ad7d42e49464267cc8e30a0d0 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Sun, 1 Aug 2021 20:44:37 +0800 Subject: [PATCH 1/4] Switch to moka-cht - Replace cht v0.4.1, the concurrent hash table implementation, with a fork, moka-cht v0.5.0. - Update value_initializer modules to replace moka-cht HashMap with SegmentedHash for better concurrency. - Temporary allow clippy::redundant_allocation [1]. This lint was introduced to Clippy 0.1.54 (beta). This will be addressed in Moka v0.6.0 as it requires changing the return type of `get_or_try_insert_with` [1]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation --- Cargo.toml | 4 ++-- README.md | 3 +-- src/future/cache.rs | 24 +++++++++++------------- src/future/value_initializer.rs | 8 ++++++-- src/lib.rs | 12 ++++++------ src/sync/base_cache.rs | 6 +++--- src/sync/cache.rs | 32 +++++++++++++++++++------------- src/sync/invalidator.rs | 2 -- src/sync/segment.rs | 4 ++++ src/sync/value_initializer.rs | 8 ++++++-- src/unsync/cache.rs | 14 ++++++-------- 11 files changed, 64 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ebc73734..bedd279a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moka" -version = "0.5.0" +version = "0.5.1" authors = ["Tatsuya Kawano "] edition = "2018" @@ -24,8 +24,8 @@ default = [] future = ["async-io", "async-lock"] [dependencies] -cht = "0.4" crossbeam-channel = "0.5" +moka-cht = "0.5" num_cpus = "1.13" once_cell = "1.7" parking_lot = "0.11" diff --git a/README.md b/README.md index 7d9a0d7f..c4b87c0f 100644 --- a/README.md +++ b/README.md @@ -330,8 +330,7 @@ change. diff --git a/src/future/cache.rs b/src/future/cache.rs index a2778a6f..656da349 100644 --- a/src/future/cache.rs +++ b/src/future/cache.rs @@ -27,14 +27,14 @@ use std::{ /// `Cache` supports full concurrency of retrievals and a high expected concurrency /// for updates. It can be accessed inside and outside of asynchronous contexts. /// -/// `Cache` utilizes a lock-free concurrent hash table `cht::SegmentedHashMap` from -/// the [cht][cht-crate] crate for the central key-value storage. `Cache` performs a -/// best-effort bounding of the map using an entry replacement algorithm to determine -/// which entries to evict when the capacity is exceeded. +/// `Cache` utilizes a lock-free concurrent hash table `SegmentedHashMap` from the +/// [moka-cht][moka-cht-crate] crate for the central key-value storage. `Cache` +/// performs a best-effort bounding of the map using an entry replacement algorithm +/// to determine which entries to evict when the capacity is exceeded. /// /// To use this cache, enable a crate feature called "future". /// -/// [cht-crate]: https://crates.io/crates/cht +/// [moka-cht-crate]: https://crates.io/crates/moka-cht /// /// # Examples /// @@ -171,15 +171,13 @@ use std::{ /// # Hashing Algorithm /// /// By default, `Cache` uses a hashing algorithm selected to provide resistance -/// against HashDoS attacks. +/// against HashDoS attacks. It will be the same one used by +/// `std::collections::HashMap`, which is currently SipHash 1-3. /// -/// The default hashing algorithm is the one used by `std::collections::HashMap`, -/// which is currently SipHash 1-3. -/// -/// While its performance is very competitive for medium sized keys, other hashing -/// algorithms will outperform it for small keys such as integers as well as large -/// keys such as long strings. However those algorithms will typically not protect -/// against attacks such as HashDoS. +/// While SipHash's performance is very competitive for medium sized keys, other +/// hashing algorithms will outperform it for small keys such as integers as well as +/// large keys such as long strings. However those algorithms will typically not +/// protect against attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`Cache` basis using the /// [`build_with_hasher`][build-with-hasher-method] method of the diff --git a/src/future/value_initializer.rs b/src/future/value_initializer.rs index e64fe485..7e2ebc72 100644 --- a/src/future/value_initializer.rs +++ b/src/future/value_initializer.rs @@ -8,14 +8,18 @@ use std::{ type Waiter = Arc>>>>>; +#[allow(clippy::redundant_allocation)] +// https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation pub(crate) enum InitResult { Initialized(V), ReadExisting(V), + // This `Arc>` creates an extra heap allocation. This will be + // addressed by Moka v0.6.0. InitErr(Arc>), } pub(crate) struct ValueInitializer { - waiters: cht::HashMap, Waiter, S>, + waiters: moka_cht::SegmentedHashMap, Waiter, S>, } impl ValueInitializer @@ -26,7 +30,7 @@ where { pub(crate) fn with_hasher(hasher: S) -> Self { Self { - waiters: cht::HashMap::with_hasher(hasher), + waiters: moka_cht::SegmentedHashMap::with_num_segments_and_hasher(16, hasher), } } diff --git a/src/lib.rs b/src/lib.rs index 7d8e8da6..28886e1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,19 +6,19 @@ //! //! Moka provides in-memory concurrent cache implementations that support full //! concurrency of retrievals and a high expected concurrency for updates. -//! They utilize a lock-free concurrent hash table `cht::SegmentedHashMap` from the -//! [cht][cht-crate] crate for the central key-value storage. +//! They utilize a lock-free concurrent hash table `SegmentedHashMap` from the +//! [moka-cht][moka-cht-crate] crate for the central key-value storage. //! //! Moka also provides an in-memory, not thread-safe cache implementation for single //! thread applications. //! -//! All cache implementations perform a best-effort bounding of the map using an entry -//! replacement algorithm to determine which entries to evict when the capacity is -//! exceeded. +//! All cache implementations perform a best-effort bounding of the map using an +//! entry replacement algorithm to determine which entries to evict when the capacity +//! is exceeded. //! //! [caffeine-git]: https://github.com/ben-manes/caffeine //! [ristretto-git]: https://github.com/dgraph-io/ristretto -//! [cht-crate]: https://crates.io/crates/cht +//! [moka-cht-crate]: https://crates.io/crates/moka-cht //! //! # Features //! diff --git a/src/sync/base_cache.rs b/src/sync/base_cache.rs index afb125ff..167fbbed 100644 --- a/src/sync/base_cache.rs +++ b/src/sync/base_cache.rs @@ -236,7 +236,7 @@ where let mut op1 = None; let mut op2 = None; - // Since the cache (cht::SegmentedHashMap) employs optimistic locking + // Since the cache (moka-cht::SegmentedHashMap) employs optimistic locking // strategy, insert_with_or_modify() may get an insert/modify operation // conflicted with other concurrent hash table operations. In that case, it // has to retry the insertion or modification, so on_insert and/or on_modify @@ -343,7 +343,7 @@ where } } -type CacheStore = cht::SegmentedHashMap, Arc>, S>; +type CacheStore = moka_cht::SegmentedHashMap, Arc>, S>; type CacheEntry = (Arc, Arc>); @@ -387,7 +387,7 @@ where .map(|cap| cap + WRITE_LOG_SIZE * 4) .unwrap_or_default(); let num_segments = 64; - let cache = cht::SegmentedHashMap::with_num_segments_capacity_and_hasher( + let cache = moka_cht::SegmentedHashMap::with_num_segments_capacity_and_hasher( num_segments, initial_capacity, build_hasher.clone(), diff --git a/src/sync/cache.rs b/src/sync/cache.rs index 7f6e4b17..0dd9cccb 100644 --- a/src/sync/cache.rs +++ b/src/sync/cache.rs @@ -21,12 +21,12 @@ use std::{ /// `Cache` supports full concurrency of retrievals and a high expected concurrency /// for updates. /// -/// `Cache` utilizes a lock-free concurrent hash table `cht::SegmentedHashMap` from -/// the [cht][cht-crate] crate for the central key-value storage. `Cache` performs a -/// best-effort bounding of the map using an entry replacement algorithm to determine -/// which entries to evict when the capacity is exceeded. +/// `Cache` utilizes a lock-free concurrent hash table `SegmentedHashMap` from the +/// [moka-cht][moka-cht-crate] crate for the central key-value storage. `Cache` +/// performs a best-effort bounding of the map using an entry replacement algorithm +/// to determine which entries to evict when the capacity is exceeded. /// -/// [cht-crate]: https://crates.io/crates/cht +/// [moka-cht-crate]: https://crates.io/crates/moka-cht /// /// # Examples /// @@ -143,15 +143,13 @@ use std::{ /// # Hashing Algorithm /// /// By default, `Cache` uses a hashing algorithm selected to provide resistance -/// against HashDoS attacks. +/// against HashDoS attacks. It will be the same one used by +/// `std::collections::HashMap`, which is currently SipHash 1-3. /// -/// The default hashing algorithm is the one used by `std::collections::HashMap`, -/// which is currently SipHash 1-3. -/// -/// While its performance is very competitive for medium sized keys, other hashing -/// algorithms will outperform it for small keys such as integers as well as large -/// keys such as long strings. However those algorithms will typically not protect -/// against attacks such as HashDoS. +/// While SipHash's performance is very competitive for medium sized keys, other +/// hashing algorithms will outperform it for small keys such as integers as well as +/// large keys such as long strings. However those algorithms will typically not +/// protect against attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`Cache` basis using the /// [`build_with_hasher`][build-with-hasher-method] method of the @@ -295,6 +293,10 @@ where /// key even if the method is concurrently called by many threads; only one of /// the calls evaluates its function, and other calls wait for that function to /// complete. + #[allow(clippy::redundant_allocation)] + // https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation + // `Arc>` in the return type creates an extra heap allocation. + // This will be addressed by Moka v0.6.0. pub fn get_or_try_insert_with( &self, key: K, @@ -308,6 +310,10 @@ where self.get_or_try_insert_with_hash_and_fun(key, hash, init) } + #[allow(clippy::redundant_allocation)] + // https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation + // `Arc>` in the return type creates an extra heap allocation. + // This will be addressed by Moka v0.6.0. pub(crate) fn get_or_try_insert_with_hash_and_fun( &self, key: Arc, diff --git a/src/sync/invalidator.rs b/src/sync/invalidator.rs index 465391b2..8f3985fe 100644 --- a/src/sync/invalidator.rs +++ b/src/sync/invalidator.rs @@ -73,8 +73,6 @@ impl InvalidationResult { } pub(crate) struct Invalidator { - // TODO: Replace this RwLock> with cht::HashMap - // once iterator is implemented. https://github.com/Gregory-Meyer/cht/issues/20 predicates: RwLock>>, is_empty: AtomicBool, scan_context: Arc>, diff --git a/src/sync/segment.rs b/src/sync/segment.rs index 9c02338d..67c6bd77 100644 --- a/src/sync/segment.rs +++ b/src/sync/segment.rs @@ -155,6 +155,10 @@ where /// key even if the method is concurrently called by many threads; only one of /// the calls evaluates its function, and other calls wait for that function to /// complete. + #[allow(clippy::redundant_allocation)] + // https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation + // `Arc>` in the return type creates an extra heap allocation. + // This will be addressed by Moka v0.6.0. pub fn get_or_try_insert_with( &self, key: K, diff --git a/src/sync/value_initializer.rs b/src/sync/value_initializer.rs index cad10b26..44dfd282 100644 --- a/src/sync/value_initializer.rs +++ b/src/sync/value_initializer.rs @@ -7,14 +7,18 @@ use std::{ type Waiter = Arc>>>>>; +#[allow(clippy::redundant_allocation)] +// https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation pub(crate) enum InitResult { Initialized(V), ReadExisting(V), + // This `Arc>` creates an extra heap allocation. This will be + // addressed by Moka v0.6.0. InitErr(Arc>), } pub(crate) struct ValueInitializer { - waiters: cht::HashMap, Waiter, S>, + waiters: moka_cht::SegmentedHashMap, Waiter, S>, } impl ValueInitializer @@ -25,7 +29,7 @@ where { pub(crate) fn with_hasher(hasher: S) -> Self { Self { - waiters: cht::HashMap::with_hasher(hasher), + waiters: moka_cht::SegmentedHashMap::with_num_segments_and_hasher(16, hasher), } } diff --git a/src/unsync/cache.rs b/src/unsync/cache.rs index cc310235..ca4128ca 100644 --- a/src/unsync/cache.rs +++ b/src/unsync/cache.rs @@ -91,15 +91,13 @@ type CacheStore = std::collections::HashMap, ValueEntry, S> /// # Hashing Algorithm /// /// By default, `Cache` uses a hashing algorithm selected to provide resistance -/// against HashDoS attacks. +/// against HashDoS attacks. It will the same one used by +/// `std::collections::HashMap`, which is currently SipHash 1-3. /// -/// The default hashing algorithm is the one used by `std::collections::HashMap`, -/// which is currently SipHash 1-3. -/// -/// While its performance is very competitive for medium sized keys, other hashing -/// algorithms will outperform it for small keys such as integers as well as large -/// keys such as long strings. However those algorithms will typically not protect -/// against attacks such as HashDoS. +/// While SipHash's performance is very competitive for medium sized keys, other +/// hashing algorithms will outperform it for small keys such as integers as well as +/// large keys such as long strings. However those algorithms will typically not +/// protect against attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`Cache` basis using the /// [`build_with_hasher`][build-with-hasher-method] method of the From 543f3c56a51ff1a6ed65c19701bbfb496aaec657 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Sun, 1 Aug 2021 23:31:04 +0800 Subject: [PATCH 2/4] Update the CHANGELOG for Moka v0.5.1 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 798309ec..ea185062 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Moka — Change Log +## Version 0.5.1 + +### Changed + +- Replace a dependency cht v0.4.1 with moka-cht v0.5.0. ([#22][gh-pull-0022]) + + ## Version 0.5.0 ### Added @@ -74,6 +81,7 @@ [caffeine-git]: https://github.com/ben-manes/caffeine +[gh-pull-0022]: https://github.com/moka-rs/moka/pull/22/ [gh-pull-0020]: https://github.com/moka-rs/moka/pull/20/ [gh-pull-0019]: https://github.com/moka-rs/moka/pull/19/ [gh-pull-0016]: https://github.com/moka-rs/moka/pull/16/ From bdc3651370f8016c3d98f6e6655f5c13ff016adf Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Tue, 3 Aug 2021 17:35:21 +0800 Subject: [PATCH 3/4] Tweak the v0.5.1 entry in the CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea185062..c1a0008c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Changed -- Replace a dependency cht v0.4.1 with moka-cht v0.5.0. ([#22][gh-pull-0022]) +- Replace a dependency cht v0.4 with moka-cht v0.5. ([#22][gh-pull-0022]) ## Version 0.5.0 From c0a820eee638512623e1bb4a7b3b55741faa4b16 Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Tue, 3 Aug 2021 18:12:44 +0800 Subject: [PATCH 4/4] Switch to moka-cht - Update future/cache module to temporary allow clippy::redundant_allocation. This will be addressed in Moka v0.6.0 as it requires changing the return type of `get_or_try_insert_with`. --- src/future/cache.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/future/cache.rs b/src/future/cache.rs index 656da349..f06f695e 100644 --- a/src/future/cache.rs +++ b/src/future/cache.rs @@ -292,6 +292,10 @@ where /// key even if the method is concurrently called by many async tasks; only one /// of the calls resolves its future, and other calls wait for that future to /// complete. + #[allow(clippy::redundant_allocation)] + // https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation + // `Arc>` in the return type creates an extra heap allocation. + // This will be addressed by Moka v0.6.0. pub async fn get_or_try_insert_with( &self, key: K, @@ -482,6 +486,10 @@ where } } + #[allow(clippy::redundant_allocation)] + // https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation + // `Arc>` in the return type creates an extra heap allocation. + // This will be addressed by Moka v0.6.0. async fn get_or_try_insert_with_hash_and_fun( &self, key: Arc,