diff --git a/src/common/concurrent.rs b/src/common/concurrent.rs index 28303952..2f7e6d8e 100644 --- a/src/common/concurrent.rs +++ b/src/common/concurrent.rs @@ -303,7 +303,6 @@ impl AccessTime for TrioArc> { pub(crate) enum ReadOp { Hit { value_entry: TrioArc>, - timestamp: Instant, is_expiry_modified: bool, }, // u64 is the hash of the key. diff --git a/src/future/base_cache.rs b/src/future/base_cache.rs index 5c3c523b..3d20873b 100644 --- a/src/future/base_cache.rs +++ b/src/future/base_cache.rs @@ -323,12 +323,13 @@ where ); } + entry.set_last_accessed(now); + let maybe_key = if need_key { Some(Arc::clone(k)) } else { None }; let ent = Entry::new(maybe_key, entry.value.clone(), false); let maybe_op = if record_read { Some(ReadOp::Hit { value_entry: TrioArc::clone(entry), - timestamp: now, is_expiry_modified, }) } else { @@ -1586,12 +1587,10 @@ where match ch.try_recv() { Ok(Hit { value_entry, - timestamp, is_expiry_modified, }) => { let kh = value_entry.entry_info().key_hash(); freq.increment(kh.hash); - value_entry.set_last_accessed(timestamp); if is_expiry_modified { self.update_timer_wheel(&value_entry, timer_wheel); } diff --git a/src/future/cache.rs b/src/future/cache.rs index d7da9d90..c6104d98 100644 --- a/src/future/cache.rs +++ b/src/future/cache.rs @@ -2739,6 +2739,32 @@ mod tests { verify_notification_vec(&cache, actual, &expected).await; } + // https://github.com/moka-rs/moka/issues/359 + #[tokio::test] + async fn ensure_access_time_is_updated_immediately_after_read() { + let mut cache = Cache::builder() + .max_capacity(10) + .time_to_idle(Duration::from_secs(5)) + .build(); + cache.reconfigure_for_testing().await; + + let (clock, mock) = Clock::mock(); + cache.set_expiration_clock(Some(clock)).await; + + // Make the cache exterior immutable. + let cache = cache; + + cache.insert(1, 1).await; + + mock.increment(Duration::from_secs(4)); + assert_eq!(cache.get(&1).await, Some(1)); + + mock.increment(Duration::from_secs(2)); + assert_eq!(cache.get(&1).await, Some(1)); + cache.run_pending_tasks().await; + assert_eq!(cache.get(&1).await, Some(1)); + } + #[tokio::test] async fn time_to_live_by_expiry_type() { // The following `Vec`s will hold actual and expected notifications. diff --git a/src/sync/cache.rs b/src/sync/cache.rs index ff6d2601..bc7f2f8e 100644 --- a/src/sync/cache.rs +++ b/src/sync/cache.rs @@ -2407,6 +2407,32 @@ mod tests { verify_notification_vec(&cache, actual, &expected); } + // https://github.com/moka-rs/moka/issues/359 + #[test] + fn ensure_access_time_is_updated_immediately_after_read() { + let mut cache = Cache::builder() + .max_capacity(10) + .time_to_idle(Duration::from_secs(5)) + .build(); + cache.reconfigure_for_testing(); + + let (clock, mock) = Clock::mock(); + cache.set_expiration_clock(Some(clock)); + + // Make the cache exterior immutable. + let cache = cache; + + cache.insert(1, 1); + + mock.increment(Duration::from_secs(4)); + assert_eq!(cache.get(&1), Some(1)); + + mock.increment(Duration::from_secs(2)); + assert_eq!(cache.get(&1), Some(1)); + cache.run_pending_tasks(); + assert_eq!(cache.get(&1), Some(1)); + } + #[test] fn time_to_live_by_expiry_type() { // Define an expiry type. diff --git a/src/sync_base/base_cache.rs b/src/sync_base/base_cache.rs index bfb16ae3..9a52af93 100644 --- a/src/sync_base/base_cache.rs +++ b/src/sync_base/base_cache.rs @@ -349,10 +349,11 @@ where ); } + entry.set_last_accessed(now); + let v = entry.value.clone(); let op = ReadOp::Hit { value_entry: entry, - timestamp: now, is_expiry_modified, }; read_recorder(op, now); @@ -1407,12 +1408,10 @@ where match ch.try_recv() { Ok(Hit { value_entry, - timestamp, is_expiry_modified, }) => { let kh = value_entry.entry_info().key_hash(); freq.increment(kh.hash); - value_entry.set_last_accessed(timestamp); if is_expiry_modified { self.update_timer_wheel(&value_entry, timer_wheel); }