Skip to content

Feature request: non-blocking invalidate() in AsyncLoadingCache #148

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

Closed
adamw opened this issue Mar 29, 2017 · 12 comments
Closed

Feature request: non-blocking invalidate() in AsyncLoadingCache #148

adamw opened this issue Mar 29, 2017 · 12 comments

Comments

@adamw
Copy link

adamw commented Mar 29, 2017

Right now the only way to invalidate a key in AsyncLoadingCache is through the synchronous interface, which provides a blocking method. It would be great if there was an asynchronous version, which would return a CompletableFuture<Void>, which would complete when the key is invalidated.

@ben-manes
Copy link
Owner

It is blocking only to perform the hash table operation. The value isn't returned, so it won't block on the future result. I don't think that deserves an asynchronous wrapping, do you?

@adamw
Copy link
Author

adamw commented Mar 29, 2017

According to my experiments it blocks if a concurrent load is happening for a given key, see my test: https://github.com/softwaremill/cache-get-or-create/blob/master/src/main/java/com/softwaremill/TestCaffeine.java (the loader artificially sleeps for one second)

@ben-manes
Copy link
Owner

Yes, but an async cache performs a load that returns a future which is very cheap. Your test is for a sync cache where the load can be slow due to performing the user operation.

@adamw
Copy link
Author

adamw commented Mar 29, 2017

Ah! True :) And even though invalidate returns immediately, the value is invalidated after the cache completes (test here: https://github.com/softwaremill/cache-get-or-create/blob/master/src/main/java/com/softwaremill/TestCaffeineAsync.java) - which was the original problem that lead me to Caffeine.

I'll put a blog on that up tomorrow probably :) - thanks for the project

@adamw adamw closed this as completed Mar 29, 2017
@ben-manes
Copy link
Owner

Yep, it's removed and the removal notification is chained on the future. The asMap().remove(k) does block on the future since it returns the result, so invalidating demonstrates an optimization by the more opinionated API.

@adamw
Copy link
Author

adamw commented Mar 29, 2017

Managed to finish it today, here's the blog I mentioned: https://softwaremill.com/race-condition-cache-guava-caffeine/

@ben-manes
Copy link
Owner

Cool, thanks!

You might want to use getIfPresent in your code examples, as get() was confusing if familiar with the interfaces.

There is a Guava bug on the invalidation problem. Since the entry isn't loaded Guava let's removal skip, which simplifies the locking. Caffeine has the same problem on a clear since ConcurrentHashMap suppresses the keys being loaded when we iterate.

@adamw
Copy link
Author

adamw commented Mar 29, 2017

Thanks for the pointer, adding a note to the blog.

I think get is the correct one, as getIfPresent would suggest to skip the loading if the value isn't already in the cache?

@ben-manes
Copy link
Owner

In your first example get doesn't have a loader to demonstrate the race. But some libraries, like JSR107, only have get and behave differently if a loader is attached. I find that more confusing so the explicit getIfPresent and get (load) are more obvious to me, at least.

@adamw
Copy link
Author

adamw commented Mar 29, 2017

Ah there, correct, thanks, I was thinking of the later examples :)

@ben-manes
Copy link
Owner

You can use invalidate(key) from the synchronous view.

This is equivalent to the async asMap() remove(key) except doesn’t return the prior future mapping. The synchronous asMap().remove(key) does block on the future as that view has to return the value and wait until it’s resolved.

@Inego
Copy link
Contributor

Inego commented Oct 7, 2020

Thanks, Ben!
My bad, I deleted my question because I had found an answer to it in a different issue here, but you still managed to answer it 😅

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

No branches or pull requests

3 participants