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

Iterating cache #112

Closed
JRAndreassen opened this issue Apr 7, 2022 · 10 comments · Fixed by #114
Closed

Iterating cache #112

JRAndreassen opened this issue Apr 7, 2022 · 10 comments · Fixed by #114
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@JRAndreassen
Copy link

JRAndreassen commented Apr 7, 2022

Hi @tatsuya6502 ,

I'm using moka cache (moka::future)...

use moka::future::{
    Cache,
    CacheBuilder,
};
...
lazy_static!{
    static ref WEB_CACHE: ResultCache =  CacheBuilder::new(10_000) // Max 10,000 elements
            .time_to_live(Duration::from_secs(15 * 60)) // Time to live (TTL): 15 minutes
            .time_to_idle(Duration::from_secs( 5 * 60)) // Time to idle (TTI):  5 minutes
            .build();  // Create the cache.
}

It is working well...

What is the best way of iterating through the elements in the list ?

I've looked through the code trying to find a way.
A "keys(&self) -> Vec" method would work..
Then I can iterate through the normal get...
Thanks...
JR

@tatsuya6502
Copy link
Member

Hi. Currently (v0.8.1), moka::future::Cache does not provide a way to iterate through all entries or retrieve all keys in a cache. There is an experimental cache implementation called moka::dash::Cache that has iter() method, but it is not optimized for asynchronous use.

Let me spend a few days to explore some options to provide either iter() or keys() method.

Providing such a method in a concurrent collection will be much more complicated than in a not-thread-safe collection (e.g. std::collections::HashTable). This is because concurrent collections allow updates from other threads while some threads are iterating. So some experimentation will be needed.

I will get back to you when I decide what to do.

@tatsuya6502 tatsuya6502 self-assigned this Apr 8, 2022
@tatsuya6502 tatsuya6502 added the enhancement New feature or request label Apr 8, 2022
@JRAndreassen
Copy link
Author

Hi @tatsuya6502 ,

Thanks for looking into it.
The "keys() -> Vec" would work if it is easier...
JR

@tatsuya6502
Copy link
Member

I believe I found a good solution for providing iterators. Although it has some disadvantages (below), I hope it will be good enough for many use cases:

Disadvantages:

  • It's next method may not (or may) return some entries (key-value pairs) if they have inserted after the iterator was created.
  • It has some memory overheads as it creates and holds a snapshot of keys (Vec<std::sync::Weak<K>>) of an internal hash table segment:
    • Each cache has 64 segments (hard-coded since Moka v0.1.0), except sync::SegmentedCache.
    • An iterator creates and hold one snapshot of only one segment at a time.
      • So this will consume less memory than creating/holding a snapshot of the entire hash table.

Advantages:

  • It does not reduce concurrency.
    • Allows concurrent reads and writes on the cache while iterators are alive.
  • Its implementation is simple and reliable.

I found implementing such an iterator requires about the same amount of work to implement keys() -> Vec method. Since the iterator is more commonly used in Rust libraries and it will consume 64 times smaller amount of memory than keys(), I took the iterator path (#114).

@JRAndreassen
Copy link
Author

JRAndreassen commented Apr 9, 2022

@tatsuya6502 ,
Iterator works for me..
if it implements the 'core::iter::Iterator' trait, that would be awesome..

Thanks for looking into it...
JR

@tatsuya6502
Copy link
Member

tatsuya6502 commented Apr 9, 2022

@JRAndreassen,

Yes. The iter method returns an iterator, which implements the core::iter::Iteranor trait. Also &Cache implements the core::iter::IntoIterator trait.

So you can either do this (iter method):

assert_eq!(cache.iter().count(), 1);

or this (IntoIterator):

moka/src/future/cache.rs

Lines 1491 to 1495 in 52c9f55

for (key, value) in &cache {
assert_eq!(value, make_value(*key));
key_set.insert(*key);
}

@JRAndreassen
Copy link
Author

Sweet...

@tatsuya6502
Copy link
Member

@JRAndreassen — I am going to merge #114 with the iterator supports. Then, I will do some pre-release testing and release v0.8.2 in a day or so. I will let you know when v0.8.2 is released.

@JRAndreassen
Copy link
Author

@tatsuya6502 ..
Super awesome..
JR

@tatsuya6502
Copy link
Member

Hi @JRAndreassen — OK. I have published Moka v0.8.2 to crates.io. Please let me know if you have any questions.

@JRAndreassen
Copy link
Author

@tatsuya6502 ,
Excellent..
I'll be testing it here in the next few day's...
I'll let you know how it goes.

Thanks for fixing it...
JR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants