Skip to content

Commit

Permalink
Add invalidate_all method to all caches
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsuya6502 committed Feb 27, 2021
1 parent a45218a commit 3a38b70
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 160 deletions.
11 changes: 4 additions & 7 deletions CHANGELOG.md
@@ -1,17 +1,14 @@
# Moka — Release Notes
# Moka — Change Log

## Unreleased

### Features

- Introduce an unsync cache.
- Add an unsync cache (`moka::unsync::Cache`) and its builder.
- Add `invalidate_all` method to `sync`, `future` and `unsync` caches.


## Version 0.2.0

### Features

- Introduce an asynchronous (futures aware) cache.
- Add an asynchronous, futures aware cache (`moka::future::Cache`) and its builder.


## Version 0.1.0
Expand Down
8 changes: 8 additions & 0 deletions src/common.rs
Expand Up @@ -11,3 +11,11 @@ pub(crate) trait AccessTime {
fn last_modified(&self) -> Option<Instant>;
fn set_last_modified(&mut self, timestamp: Instant);
}

pub(crate) fn u64_to_instant(ts: u64) -> Option<Instant> {
if ts == u64::MAX {
None
} else {
Some(unsafe { std::mem::transmute(ts) })
}
}
32 changes: 32 additions & 0 deletions src/future/cache.rs
Expand Up @@ -327,6 +327,10 @@ where
}
}

pub fn invalidate_all(&self) {
self.base.invalidate_all();
}

/// Returns the `max_capacity` of this cache.
pub fn max_capacity(&self) -> usize {
self.base.max_capacity()
Expand Down Expand Up @@ -577,6 +581,34 @@ mod tests {
assert!(cache.get(&20).is_some());
}

#[tokio::test]
async fn invalidate_all() {
let mut cache = Cache::new(100);
cache.reconfigure_for_testing();

// Make the cache exterior immutable.
let cache = cache;

cache.insert("a", "alice").await;
cache.insert("b", "bob").await;
cache.insert("c", "cindy").await;
assert_eq!(cache.get(&"a"), Some("alice"));
assert_eq!(cache.get(&"b"), Some("bob"));
assert_eq!(cache.get(&"c"), Some("cindy"));
cache.sync();

cache.invalidate_all();
cache.sync();

cache.insert("d", "david").await;
cache.sync();

assert!(cache.get(&"a").is_none());
assert!(cache.get(&"b").is_none());
assert!(cache.get(&"c").is_none());
assert_eq!(cache.get(&"d"), Some("david"));
}

#[tokio::test]
async fn time_to_live() {
let mut cache = CacheBuilder::new(100)
Expand Down
98 changes: 27 additions & 71 deletions src/sync.rs
@@ -1,6 +1,6 @@
//! Provides thread-safe, synchronous (blocking) cache implementations.

use crate::common::{deque::DeqNode, AccessTime};
use crate::common::{deque::DeqNode, u64_to_instant, AccessTime};

use parking_lot::Mutex;
use quanta::Instant;
Expand Down Expand Up @@ -42,23 +42,23 @@ impl<K> KeyHash<K> {

pub(crate) struct KeyDate<K> {
pub(crate) key: Arc<K>,
pub(crate) timestamp: Option<Arc<AtomicU64>>,
pub(crate) timestamp: Arc<AtomicU64>,
}

impl<K> KeyDate<K> {
pub(crate) fn new(key: Arc<K>, timestamp: Option<Arc<AtomicU64>>) -> Self {
pub(crate) fn new(key: Arc<K>, timestamp: Arc<AtomicU64>) -> Self {
Self { key, timestamp }
}
}

pub(crate) struct KeyHashDate<K> {
pub(crate) key: Arc<K>,
pub(crate) hash: u64,
pub(crate) timestamp: Option<Arc<AtomicU64>>,
pub(crate) timestamp: Arc<AtomicU64>,
}

impl<K> KeyHashDate<K> {
pub(crate) fn new(kh: KeyHash<K>, timestamp: Option<Arc<AtomicU64>>) -> Self {
pub(crate) fn new(kh: KeyHash<K>, timestamp: Arc<AtomicU64>) -> Self {
Self {
key: kh.key,
hash: kh.hash,
Expand Down Expand Up @@ -86,21 +86,17 @@ unsafe impl<K> Send for DeqNodes<K> {}

pub(crate) struct ValueEntry<K, V> {
pub(crate) value: V,
last_accessed: Option<Arc<AtomicU64>>,
last_modified: Option<Arc<AtomicU64>>,
last_accessed: Arc<AtomicU64>,
last_modified: Arc<AtomicU64>,
nodes: Mutex<DeqNodes<K>>,
}

impl<K, V> ValueEntry<K, V> {
pub(crate) fn new(
value: V,
last_accessed: Option<Instant>,
last_modified: Option<Instant>,
) -> Self {
pub(crate) fn new(value: V) -> Self {
Self {
value,
last_accessed: last_accessed.map(|ts| Arc::new(AtomicU64::new(ts.as_u64()))),
last_modified: last_modified.map(|ts| Arc::new(AtomicU64::new(ts.as_u64()))),
last_accessed: Arc::new(AtomicU64::new(std::u64::MAX)),
last_modified: Arc::new(AtomicU64::new(std::u64::MAX)),
nodes: Mutex::new(DeqNodes {
access_order_q_node: None,
write_order_q_node: None,
Expand All @@ -124,11 +120,11 @@ impl<K, V> ValueEntry<K, V> {
}
}

pub(crate) fn raw_last_accessed(&self) -> Option<Arc<AtomicU64>> {
pub(crate) fn raw_last_accessed(&self) -> Arc<AtomicU64> {
self.last_accessed.clone()
}

pub(crate) fn raw_last_modified(&self) -> Option<Arc<AtomicU64>> {
pub(crate) fn raw_last_modified(&self) -> Arc<AtomicU64> {
self.last_modified.clone()
}

Expand Down Expand Up @@ -166,44 +162,24 @@ impl<K, V> ValueEntry<K, V> {
impl<K, V> AccessTime for Arc<ValueEntry<K, V>> {
#[inline]
fn last_accessed(&self) -> Option<Instant> {
self.last_accessed
.as_ref()
.map(|ts| ts.load(Ordering::Relaxed))
.and_then(|ts| {
if ts == u64::MAX {
None
} else {
Some(unsafe { std::mem::transmute(ts) })
}
})
u64_to_instant(self.last_accessed.load(Ordering::Relaxed))
}

#[inline]
fn set_last_accessed(&mut self, timestamp: Instant) {
if let Some(ts) = &self.last_accessed {
ts.store(timestamp.as_u64(), Ordering::Relaxed);
}
self.last_accessed
.store(timestamp.as_u64(), Ordering::Relaxed);
}

#[inline]
fn last_modified(&self) -> Option<Instant> {
self.last_modified
.as_ref()
.map(|ts| ts.load(Ordering::Relaxed))
.and_then(|ts| {
if ts == u64::MAX {
None
} else {
Some(unsafe { std::mem::transmute(ts) })
}
})
u64_to_instant(self.last_modified.load(Ordering::Relaxed))
}

#[inline]
fn set_last_modified(&mut self, timestamp: Instant) {
if let Some(ts) = &self.last_modified {
ts.store(timestamp.as_u64(), Ordering::Relaxed);
}
self.last_modified
.store(timestamp.as_u64(), Ordering::Relaxed);
}
}

Expand All @@ -220,48 +196,28 @@ impl<K> AccessTime for DeqNode<KeyDate<K>> {

#[inline]
fn last_modified(&self) -> Option<Instant> {
self.element
.timestamp
.as_ref()
.map(|ts| ts.load(Ordering::Relaxed))
.and_then(|ts| {
if ts == u64::MAX {
None
} else {
Some(unsafe { std::mem::transmute(ts) })
}
})
u64_to_instant(self.element.timestamp.load(Ordering::Relaxed))
}

#[inline]
fn set_last_modified(&mut self, timestamp: Instant) {
if let Some(ts) = self.element.timestamp.as_ref() {
ts.store(timestamp.as_u64(), Ordering::Relaxed);
}
self.element
.timestamp
.store(timestamp.as_u64(), Ordering::Relaxed);
}
}

impl<K> AccessTime for DeqNode<KeyHashDate<K>> {
#[inline]
fn last_accessed(&self) -> Option<Instant> {
self.element
.timestamp
.as_ref()
.map(|ts| ts.load(Ordering::Relaxed))
.and_then(|ts| {
if ts == u64::MAX {
None
} else {
Some(unsafe { std::mem::transmute(ts) })
}
})
u64_to_instant(self.element.timestamp.load(Ordering::Relaxed))
}

#[inline]
fn set_last_accessed(&mut self, timestamp: Instant) {
if let Some(ts) = self.element.timestamp.as_ref() {
ts.store(timestamp.as_u64(), Ordering::Relaxed);
}
self.element
.timestamp
.store(timestamp.as_u64(), Ordering::Relaxed);
}

#[inline]
Expand All @@ -276,7 +232,7 @@ impl<K> AccessTime for DeqNode<KeyHashDate<K>> {
}

pub(crate) enum ReadOp<K, V> {
Hit(u64, Arc<ValueEntry<K, V>>, Option<Instant>),
Hit(u64, Arc<ValueEntry<K, V>>, Instant),
Miss(u64),
}

Expand Down

0 comments on commit 3a38b70

Please sign in to comment.