diff --git a/src/dash/base_cache.rs b/src/dash/base_cache.rs index b9f96e73..dc19dae2 100644 --- a/src/dash/base_cache.rs +++ b/src/dash/base_cache.rs @@ -76,6 +76,20 @@ impl Drop for BaseCache { } } +impl BaseCache { + pub(crate) fn policy(&self) -> Policy { + self.inner.policy() + } + + pub(crate) fn entry_count(&self) -> u64 { + self.inner.entry_count() + } + + pub(crate) fn weighted_size(&self) -> u64 { + self.inner.weighted_size() + } +} + impl BaseCache where K: Hash + Eq + Send + Sync + 'static, @@ -203,20 +217,6 @@ where let now = self.inner.current_time_from_expiration_clock(); self.inner.set_valid_after(now); } - - pub(crate) fn policy(&self) -> Policy { - self.inner.policy() - } - - #[cfg(test)] - pub(crate) fn estimated_entry_count(&self) -> u64 { - self.inner.estimated_entry_count() - } - - #[cfg(test)] - pub(crate) fn weighted_size(&self) -> u64 { - self.inner.weighted_size() - } } impl<'a, K, V, S> BaseCache @@ -555,13 +555,11 @@ impl Inner { self.time_to_idle } - #[cfg(test)] #[inline] - fn estimated_entry_count(&self) -> u64 { + fn entry_count(&self) -> u64 { self.entry_count.load() } - #[cfg(test)] #[inline] pub(crate) fn weighted_size(&self) -> u64 { self.weighted_size.load() diff --git a/src/dash/cache.rs b/src/dash/cache.rs index 3f82945d..72091920 100644 --- a/src/dash/cache.rs +++ b/src/dash/cache.rs @@ -304,6 +304,65 @@ where } } +impl Cache { + /// Returns a read-only cache policy of this cache. + /// + /// At this time, cache policy cannot be modified after cache creation. + /// A future version may support to modify it. + pub fn policy(&self) -> Policy { + self.base.policy() + } + + /// Returns an approximate number of entries in this cache. + /// + /// The value returned is _an estimate_; the actual count may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. + /// + /// # Example + /// + /// ```rust + /// use moka::dash::Cache; + /// + /// let cache = Cache::new(10); + /// cache.insert('n', "Netherland Dwarf"); + /// cache.insert('l', "Lop Eared"); + /// cache.insert('d', "Dutch"); + /// + /// // Ensure an entry exists. + /// assert!(cache.contains_key(&'n')); + /// + /// // However, followings may print stale number zeros instead of threes. + /// println!("{}", cache.entry_count()); // -> 0 + /// println!("{}", cache.weighted_size()); // -> 0 + /// + /// // To mitigate the inaccuracy, bring `ConcurrentCacheExt` trait to + /// // the scope so we can use `sync` method. + /// use moka::dash::ConcurrentCacheExt; + /// // Call `sync` to run pending internal tasks. + /// cache.sync(); + /// + /// // Followings will print the actual numbers. + /// println!("{}", cache.entry_count()); // -> 3 + /// println!("{}", cache.weighted_size()); // -> 3 + /// ``` + /// + pub fn entry_count(&self) -> u64 { + self.base.entry_count() + } + + /// Returns an approximate total weighted size of entries in this cache. + /// + /// The value returned is _an estimate_; the actual size may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. See [`entry_count`](#method.entry_count) for a sample code. + pub fn weighted_size(&self) -> u64 { + self.base.weighted_size() + } +} + impl Cache where K: Hash + Eq + Send + Sync + 'static, @@ -419,24 +478,6 @@ where pub fn invalidate_all(&self) { self.base.invalidate_all(); } - - /// Returns a read-only cache policy of this cache. - /// - /// At this time, cache policy cannot be modified after cache creation. - /// A future version may support to modify it. - pub fn policy(&self) -> Policy { - self.base.policy() - } - - #[cfg(test)] - pub(crate) fn estimated_entry_count(&self) -> u64 { - self.base.estimated_entry_count() - } - - #[cfg(test)] - pub(crate) fn weighted_size(&self) -> u64 { - self.base.weighted_size() - } } impl<'a, K, V, S> Cache @@ -552,7 +593,7 @@ where S: BuildHasher + Clone + Send + Sync + 'static, { pub(crate) fn is_table_empty(&self) -> bool { - self.estimated_entry_count() == 0 + self.entry_count() == 0 } pub(crate) fn reconfigure_for_testing(&mut self) { @@ -725,7 +766,7 @@ mod tests { assert!(!cache.contains_key(&"d")); // Verify the sizes. - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.weighted_size(), 25); } @@ -827,14 +868,14 @@ mod tests { cache.insert("b", "bob"); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 15 secs. cache.sync(); assert_eq!(cache.get(&"b"), Some("bob")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); cache.insert("b", "bill"); cache.sync(); @@ -844,7 +885,7 @@ mod tests { assert_eq!(cache.get(&"b"), Some("bill")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 25 secs assert_eq!(cache.get(&"a"), None); @@ -887,7 +928,7 @@ mod tests { cache.insert("b", "bob"); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(2)); // 12 secs. cache.sync(); @@ -897,7 +938,7 @@ mod tests { assert!(cache.contains_key(&"b")); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(3)); // 15 secs. assert_eq!(cache.get(&"a"), None); @@ -908,7 +949,7 @@ mod tests { assert_eq!(cache.iter().count(), 1); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(10)); // 25 secs assert_eq!(cache.get(&"a"), None); diff --git a/src/future/cache.rs b/src/future/cache.rs index 46e21563..640ebd9a 100644 --- a/src/future/cache.rs +++ b/src/future/cache.rs @@ -314,6 +314,79 @@ impl Clone for Cache { } } +impl Cache { + /// Returns a read-only cache policy of this cache. + /// + /// At this time, cache policy cannot be modified after cache creation. + /// A future version may support to modify it. + pub fn policy(&self) -> Policy { + self.base.policy() + } + + /// Returns an approximate number of entries in this cache. + /// + /// The value returned is _an estimate_; the actual count may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. + /// + /// # Example + /// + /// ```rust + /// // Cargo.toml + /// // + /// // [dependencies] + /// // moka = { version = "0.8", features = ["future"] } + /// // tokio = { version = "1", features = ["rt-multi-thread", "macros" ] } + /// use moka::future::Cache; + /// + /// #[tokio::main] + /// async fn main() { + /// let cache = Cache::new(10); + /// cache.insert('n', "Netherland Dwarf").await; + /// cache.insert('l', "Lop Eared").await; + /// cache.insert('d', "Dutch").await; + /// + /// // Ensure an entry exists. + /// assert!(cache.contains_key(&'n')); + /// + /// // However, followings may print stale number zeros instead of threes. + /// println!("{}", cache.entry_count()); // -> 0 + /// println!("{}", cache.weighted_size()); // -> 0 + /// + /// // To mitigate the inaccuracy, bring `ConcurrentCacheExt` trait to + /// // the scope so we can use `sync` method. + /// use moka::future::ConcurrentCacheExt; + /// // Call `sync` to run pending internal tasks. + /// cache.sync(); + /// + /// // Followings will print the actual numbers. + /// println!("{}", cache.entry_count()); // -> 3 + /// println!("{}", cache.weighted_size()); // -> 3 + /// } + /// ``` + /// + pub fn entry_count(&self) -> u64 { + self.base.entry_count() + } + + /// Returns an approximate total weighted size of entries in this cache. + /// + /// The value returned is _an estimate_; the actual size may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. See [`entry_count`](#method.entry_count) for a sample code. + pub fn weighted_size(&self) -> u64 { + self.base.weighted_size() + } + + #[cfg(feature = "unstable-debug-counters")] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable-debug-counters")))] + pub fn debug_stats(&self) -> CacheDebugStats { + self.base.debug_stats() + } +} + impl Cache where K: Hash + Eq + Send + Sync + 'static, @@ -799,30 +872,6 @@ where pub fn blocking(&self) -> BlockingOp<'_, K, V, S> { BlockingOp(self) } - - /// Returns a read-only cache policy of this cache. - /// - /// At this time, cache policy cannot be modified after cache creation. - /// A future version may support to modify it. - pub fn policy(&self) -> Policy { - self.base.policy() - } - - #[cfg(feature = "unstable-debug-counters")] - #[cfg_attr(docsrs, doc(cfg(feature = "unstable-debug-counters")))] - pub fn debug_stats(&self) -> CacheDebugStats { - self.base.debug_stats() - } - - #[cfg(test)] - fn estimated_entry_count(&self) -> u64 { - self.base.estimated_entry_count() - } - - #[cfg(test)] - fn weighted_size(&self) -> u64 { - self.base.weighted_size() - } } impl<'a, K, V, S> IntoIterator for &'a Cache @@ -991,7 +1040,7 @@ where S: BuildHasher + Clone + Send + Sync + 'static, { fn is_table_empty(&self) -> bool { - self.estimated_entry_count() == 0 + self.entry_count() == 0 } fn invalidation_predicate_count(&self) -> usize { @@ -1247,7 +1296,7 @@ mod tests { assert!(!cache.contains_key(&"d")); // Verify the sizes. - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.weighted_size(), 25); } @@ -1376,7 +1425,7 @@ mod tests { assert!(!cache.contains_key(&2)); assert!(cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.invalidation_predicate_count(), 0); mock.increment(Duration::from_secs(5)); // 15 secs from the start. @@ -1397,7 +1446,7 @@ mod tests { assert!(!cache.contains_key(&1)); assert!(!cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 0); + assert_eq!(cache.entry_count(), 0); assert_eq!(cache.invalidation_predicate_count(), 0); Ok(()) @@ -1439,14 +1488,14 @@ mod tests { cache.insert("b", "bob").await; cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 15 secs. cache.sync(); assert_eq!(cache.get(&"b"), Some("bob")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); cache.insert("b", "bill").await; cache.sync(); @@ -1456,7 +1505,7 @@ mod tests { assert_eq!(cache.get(&"b"), Some("bill")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 25 secs @@ -1500,7 +1549,7 @@ mod tests { cache.insert("b", "bob").await; cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(2)); // 12 secs. cache.sync(); @@ -1510,7 +1559,7 @@ mod tests { assert!(cache.contains_key(&"b")); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(3)); // 15 secs. assert_eq!(cache.get(&"a"), None); @@ -1521,7 +1570,7 @@ mod tests { assert_eq!(cache.iter().count(), 1); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(10)); // 25 secs assert_eq!(cache.get(&"a"), None); diff --git a/src/sync/base_cache.rs b/src/sync/base_cache.rs index f2f91d72..8cc79d2f 100644 --- a/src/sync/base_cache.rs +++ b/src/sync/base_cache.rs @@ -86,6 +86,25 @@ impl Drop for BaseCache { } } +impl BaseCache { + pub(crate) fn policy(&self) -> Policy { + self.inner.policy() + } + + pub(crate) fn entry_count(&self) -> u64 { + self.inner.entry_count() + } + + pub(crate) fn weighted_size(&self) -> u64 { + self.inner.weighted_size() + } + + #[cfg(feature = "unstable-debug-counters")] + pub fn debug_stats(&self) -> CacheDebugStats { + self.inner.debug_stats() + } +} + impl BaseCache where K: Hash + Eq + Send + Sync + 'static, @@ -225,25 +244,6 @@ where let now = self.inner.current_time_from_expiration_clock(); self.inner.register_invalidation_predicate(predicate, now) } - - pub(crate) fn policy(&self) -> Policy { - self.inner.policy() - } - - #[cfg(feature = "unstable-debug-counters")] - pub fn debug_stats(&self) -> CacheDebugStats { - self.inner.debug_stats() - } - - #[cfg(test)] - pub(crate) fn estimated_entry_count(&self) -> u64 { - self.inner.estimated_entry_count() - } - - #[cfg(test)] - pub(crate) fn weighted_size(&self) -> u64 { - self.inner.weighted_size() - } } // @@ -540,6 +540,36 @@ pub(crate) struct Inner { expiration_clock: RwLock>, } +// functions/methods used by BaseCache +impl Inner { + fn policy(&self) -> Policy { + Policy::new(self.max_capacity, 1, self.time_to_live, self.time_to_idle) + } + + #[inline] + fn entry_count(&self) -> u64 { + self.entry_count.load() + } + + #[inline] + pub(crate) fn weighted_size(&self) -> u64 { + self.weighted_size.load() + } + + #[cfg(feature = "unstable-debug-counters")] + pub fn debug_stats(&self) -> CacheDebugStats { + let ec = self.entry_count.load(); + let ws = self.weighted_size.load(); + + CacheDebugStats::new( + ec, + ws, + (self.cache.capacity() * 2) as u64, + self.frequency_sketch.read().table_size(), + ) + } +} + // functions/methods used by BaseCache impl Inner where @@ -653,10 +683,6 @@ where self.cache.actual_num_segments() } - fn policy(&self) -> Policy { - Policy::new(self.max_capacity, 1, self.time_to_live, self.time_to_idle) - } - #[inline] fn time_to_live(&self) -> Option { self.time_to_live @@ -667,31 +693,6 @@ where self.time_to_idle } - #[cfg(feature = "unstable-debug-counters")] - pub fn debug_stats(&self) -> CacheDebugStats { - let ec = self.entry_count.load(); - let ws = self.weighted_size.load(); - - CacheDebugStats::new( - ec, - ws, - (self.cache.capacity() * 2) as u64, - self.frequency_sketch.read().table_size(), - ) - } - - #[cfg(test)] - #[inline] - fn estimated_entry_count(&self) -> u64 { - self.entry_count.load() - } - - #[cfg(test)] - #[inline] - pub(crate) fn weighted_size(&self) -> u64 { - self.weighted_size.load() - } - #[inline] fn has_expiry(&self) -> bool { self.time_to_live.is_some() || self.time_to_idle.is_some() diff --git a/src/sync/cache.rs b/src/sync/cache.rs index 0eb42963..88007aa2 100644 --- a/src/sync/cache.rs +++ b/src/sync/cache.rs @@ -2,10 +2,10 @@ use super::{ base_cache::{BaseCache, HouseKeeperArc, MAX_SYNC_REPEATS, WRITE_RETRY_INTERVAL_MICROS}, housekeeper::InnerSync, iter::{Iter, ScanningGet}, - value_initializer::ValueInitializer, + value_initializer::{InitResult, ValueInitializer}, CacheBuilder, ConcurrentCacheExt, PredicateId, Weigher, WriteOp, }; -use crate::{sync::value_initializer::InitResult, Policy, PredicateError}; +use crate::{Policy, PredicateError}; use crossbeam_channel::{Sender, TrySendError}; use std::{ @@ -263,6 +263,65 @@ impl Clone for Cache { } } +impl Cache { + /// Returns a read-only cache policy of this cache. + /// + /// At this time, cache policy cannot be modified after cache creation. + /// A future version may support to modify it. + pub fn policy(&self) -> Policy { + self.base.policy() + } + + /// Returns an approximate number of entries in this cache. + /// + /// The value returned is _an estimate_; the actual count may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. + /// + /// # Example + /// + /// ```rust + /// use moka::sync::Cache; + /// + /// let cache = Cache::new(10); + /// cache.insert('n', "Netherland Dwarf"); + /// cache.insert('l', "Lop Eared"); + /// cache.insert('d', "Dutch"); + /// + /// // Ensure an entry exists. + /// assert!(cache.contains_key(&'n')); + /// + /// // However, followings may print stale number zeros instead of threes. + /// println!("{}", cache.entry_count()); // -> 0 + /// println!("{}", cache.weighted_size()); // -> 0 + /// + /// // To mitigate the inaccuracy, bring `ConcurrentCacheExt` trait to + /// // the scope so we can use `sync` method. + /// use moka::sync::ConcurrentCacheExt; + /// // Call `sync` to run pending internal tasks. + /// cache.sync(); + /// + /// // Followings will print the actual numbers. + /// println!("{}", cache.entry_count()); // -> 3 + /// println!("{}", cache.weighted_size()); // -> 3 + /// ``` + /// + pub fn entry_count(&self) -> u64 { + self.base.entry_count() + } + + /// Returns an approximate total weighted size of entries in this cache. + /// + /// The value returned is _an estimate_; the actual size may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. See [`entry_count`](#method.entry_count) for a sample code. + pub fn weighted_size(&self) -> u64 { + self.base.weighted_size() + } +} + impl Cache where K: Hash + Eq + Send + Sync + 'static, @@ -787,24 +846,6 @@ where pub fn iter(&self) -> Iter<'_, K, V> { Iter::with_single_cache_segment(&self.base, self.num_cht_segments()) } - - /// Returns a read-only cache policy of this cache. - /// - /// At this time, cache policy cannot be modified after cache creation. - /// A future version may support to modify it. - pub fn policy(&self) -> Policy { - self.base.policy() - } - - #[cfg(test)] - pub(crate) fn estimated_entry_count(&self) -> u64 { - self.base.estimated_entry_count() - } - - #[cfg(test)] - pub(crate) fn weighted_size(&self) -> u64 { - self.base.weighted_size() - } } impl<'a, K, V, S> IntoIterator for &'a Cache @@ -900,7 +941,7 @@ where S: BuildHasher + Clone + Send + Sync + 'static, { pub(crate) fn is_table_empty(&self) -> bool { - self.estimated_entry_count() == 0 + self.entry_count() == 0 } pub(crate) fn invalidation_predicate_count(&self) -> usize { @@ -1077,7 +1118,7 @@ mod tests { assert!(!cache.contains_key(&"d")); // Verify the sizes. - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.weighted_size(), 25); } @@ -1199,7 +1240,7 @@ mod tests { assert!(!cache.contains_key(&2)); assert!(cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.invalidation_predicate_count(), 0); mock.increment(Duration::from_secs(5)); // 15 secs from the start. @@ -1220,7 +1261,7 @@ mod tests { assert!(!cache.contains_key(&1)); assert!(!cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 0); + assert_eq!(cache.entry_count(), 0); assert_eq!(cache.invalidation_predicate_count(), 0); Ok(()) @@ -1262,14 +1303,14 @@ mod tests { cache.insert("b", "bob"); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 15 secs. cache.sync(); assert_eq!(cache.get(&"b"), Some("bob")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); cache.insert("b", "bill"); cache.sync(); @@ -1279,7 +1320,7 @@ mod tests { assert_eq!(cache.get(&"b"), Some("bill")); assert!(cache.contains_key(&"b")); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(5)); // 25 secs @@ -1323,7 +1364,7 @@ mod tests { cache.insert("b", "bob"); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(2)); // 12 secs. cache.sync(); @@ -1333,7 +1374,7 @@ mod tests { assert!(cache.contains_key(&"b")); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); mock.increment(Duration::from_secs(3)); // 15 secs. assert_eq!(cache.get(&"a"), None); @@ -1344,7 +1385,7 @@ mod tests { assert_eq!(cache.iter().count(), 1); cache.sync(); - assert_eq!(cache.estimated_entry_count(), 1); + assert_eq!(cache.entry_count(), 1); mock.increment(Duration::from_secs(10)); // 25 secs assert_eq!(cache.get(&"a"), None); diff --git a/src/sync/debug_counters.rs b/src/sync/debug_counters.rs index d1987e61..602ea8ec 100644 --- a/src/sync/debug_counters.rs +++ b/src/sync/debug_counters.rs @@ -108,7 +108,7 @@ impl InternalGlobalDebugCounters { #[derive(Clone, Debug)] pub struct CacheDebugStats { - pub estimated_entry_count: u64, + pub entry_count: u64, pub weighted_size: u64, // bytes pub freq_sketch_size: u64, @@ -118,13 +118,13 @@ pub struct CacheDebugStats { impl CacheDebugStats { pub(crate) fn new( - estimated_entry_count: u64, + entry_count: u64, weighted_size: u64, hashmap_capacity: u64, freq_sketch_size: u64, ) -> Self { Self { - estimated_entry_count, + entry_count, weighted_size, freq_sketch_size, hashmap_capacity, diff --git a/src/sync/segment.rs b/src/sync/segment.rs index 0d287dbb..58751e90 100644 --- a/src/sync/segment.rs +++ b/src/sync/segment.rs @@ -96,6 +96,76 @@ where } } +impl SegmentedCache { + /// Returns a read-only cache policy of this cache. + /// + /// At this time, cache policy cannot be modified after cache creation. + /// A future version may support to modify it. + pub fn policy(&self) -> Policy { + let mut policy = self.inner.segments[0].policy(); + policy.set_max_capacity(self.inner.desired_capacity); + policy.set_num_segments(self.inner.segments.len()); + policy + } + + /// Returns an approximate number of entries in this cache. + /// + /// The value returned is _an estimate_; the actual count may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. + /// + /// # Example + /// + /// ```rust + /// use moka::sync::SegmentedCache; + /// + /// let cache = SegmentedCache::new(10, 4); + /// cache.insert('n', "Netherland Dwarf"); + /// cache.insert('l', "Lop Eared"); + /// cache.insert('d', "Dutch"); + /// + /// // Ensure an entry exists. + /// assert!(cache.contains_key(&'n')); + /// + /// // However, followings may print stale number zeros instead of threes. + /// println!("{}", cache.entry_count()); // -> 0 + /// println!("{}", cache.weighted_size()); // -> 0 + /// + /// // To mitigate the inaccuracy, bring `ConcurrentCacheExt` trait to + /// // the scope so we can use `sync` method. + /// use moka::sync::ConcurrentCacheExt; + /// // Call `sync` to run pending internal tasks. + /// cache.sync(); + /// + /// // Followings will print the actual numbers. + /// println!("{}", cache.entry_count()); // -> 3 + /// println!("{}", cache.weighted_size()); // -> 3 + /// ``` + /// + pub fn entry_count(&self) -> u64 { + self.inner + .segments + .iter() + .map(|seg| seg.entry_count()) + .sum() + } + + /// Returns an approximate total weighted size of entries in this cache. + /// + /// The value returned is _an estimate_; the actual size may differ if there are + /// concurrent insertions or removals, or if some entries are pending removal due + /// to expiration. This inaccuracy can be mitigated by performing a `sync()` + /// first. See [`entry_count`](#method.entry_count) for a sample code. + pub fn weighted_size(&self) -> u64 { + self.inner + .segments + .iter() + .map(|seg| seg.weighted_size()) + .sum() + } +} + impl SegmentedCache where K: Hash + Eq + Send + Sync + 'static, @@ -372,35 +442,6 @@ where Iter::with_multiple_cache_segments(segments, num_cht_segments) } - /// Returns a read-only cache policy of this cache. - /// - /// At this time, cache policy cannot be modified after cache creation. - /// A future version may support to modify it. - pub fn policy(&self) -> Policy { - let mut policy = self.inner.segments[0].policy(); - policy.set_max_capacity(self.inner.desired_capacity); - policy.set_num_segments(self.inner.segments.len()); - policy - } - - #[cfg(test)] - fn estimated_entry_count(&self) -> u64 { - self.inner - .segments - .iter() - .map(|seg| seg.estimated_entry_count()) - .sum() - } - - #[cfg(test)] - fn weighted_size(&self) -> u64 { - self.inner - .segments - .iter() - .map(|seg| seg.weighted_size()) - .sum() - } - // /// This is used by unit tests to get consistent result. // #[cfg(test)] // pub(crate) fn reconfigure_for_testing(&mut self) { @@ -758,7 +799,7 @@ mod tests { assert!(!cache.contains_key(&"d")); // Verify the sizes. - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.weighted_size(), 25); } @@ -888,7 +929,7 @@ mod tests { assert!(!cache.contains_key(&2)); assert!(cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 2); + assert_eq!(cache.entry_count(), 2); assert_eq!(cache.invalidation_predicate_count(), 0); mock.increment(Duration::from_secs(5)); // 15 secs from the start. @@ -909,7 +950,7 @@ mod tests { assert!(!cache.contains_key(&1)); assert!(!cache.contains_key(&3)); - assert_eq!(cache.estimated_entry_count(), 0); + assert_eq!(cache.entry_count(), 0); assert_eq!(cache.invalidation_predicate_count(), 0); Ok(()) diff --git a/src/unsync/cache.rs b/src/unsync/cache.rs index e1655ab1..e03487af 100644 --- a/src/unsync/cache.rs +++ b/src/unsync/cache.rs @@ -205,6 +205,47 @@ where // // public // +impl Cache { + /// Returns a read-only cache policy of this cache. + /// + /// At this time, cache policy cannot be modified after cache creation. + /// A future version may support to modify it. + pub fn policy(&self) -> Policy { + Policy::new(self.max_capacity, 1, self.time_to_live, self.time_to_idle) + } + + /// Returns the number of entries in this cache. + /// + /// # Example + /// + /// ```rust + /// use moka::unsync::Cache; + /// + /// let mut cache = Cache::new(10); + /// cache.insert('n', "Netherland Dwarf"); + /// cache.insert('l', "Lop Eared"); + /// cache.insert('d', "Dutch"); + /// + /// // Ensure an entry exists. + /// assert!(cache.contains_key(&'n')); + /// + /// // Followings will print the actual numbers. + /// println!("{}", cache.entry_count()); // -> 3 + /// println!("{}", cache.weighted_size()); // -> 3 + /// ``` + /// + pub fn entry_count(&self) -> u64 { + self.entry_count + } + + /// Returns the total weighted size of entries in this cache. + /// + /// See [`entry_count`](#method.entry_count) for a sample code. + pub fn weighted_size(&self) -> u64 { + self.weighted_size + } +} + impl Cache where K: Hash + Eq, @@ -424,14 +465,6 @@ where pub fn iter(&self) -> Iter<'_, K, V, S> { Iter::new(self, self.cache.iter()) } - - /// Returns a read-only cache policy of this cache. - /// - /// At this time, cache policy cannot be modified after cache creation. - /// A future version may support to modify it. - pub fn policy(&self) -> Policy { - Policy::new(self.max_capacity, 1, self.time_to_live, self.time_to_idle) - } } // @@ -1124,8 +1157,8 @@ mod tests { assert!(!cache.contains_key(&"d")); // Verify the sizes. - assert_eq!(cache.entry_count, 2); - assert_eq!(cache.weighted_size, 25); + assert_eq!(cache.entry_count(), 2); + assert_eq!(cache.weighted_size(), 25); } #[test]