Concurrency issue between get(K key, Callable<? extends V> valueLoader) and invalidate(Object key)
See original GitHub issueHi,
I encountered a concurrency issue between the “get(K key, Callable<? extends V> valueLoader)” and “invalidate(Object key)” methods with a basic (and i suppose a common) usage of the cache which let a stale value in the cache.
Here is the use case:
- The cache is initially empty
- 1 thread is getting a value in the callable with a given key while an other thread is invalidating the same given key
Thread 1
Bean myBean = cache.get(ID, new Callable<Bean>() {
@Override
public Bean call() throws Exception {
Bean bean = loadFromDB(ID); // (1)
return bean; // (4)
}
});
Thread 2
// Update just one property of the bean in DB
updatePartialDataInDB(ID, "newValue1"); // (2)
// Then, we need to invalidate the cache
cache.invalidate(ID); // (3)
The execution sequence order is marked with // (number) After the point // 4, I have the old object in myBean variable which is fine. However, If i try to get again the bean with the identifier ID, I expect to have no value in the cache but a fresh bean reloaded from the DB. Unfortunately, that is not the case and a stale value is kept in the cache.
Is that a wanted behavior?
In LocalCache$Segment#remove(Object key, int hash) line 3081 to 3087 (guava 17.0):
RemovalCause cause;
if (entryValue != null) {
cause = RemovalCause.EXPLICIT;
} else if (valueReference.isActive()) {
cause = RemovalCause.COLLECTED;
} else {
// currently loading
return null;
}
Shouldn’t a particular process be done before return null ?
Thanks
Issue Analytics
- State:
- Created 9 years ago
- Reactions:3
- Comments:17 (9 by maintainers)
Top GitHub Comments
This is causing some very serious issues for us. I would argue that anyone using a lazy-loading cache would expect a happens-before relationship between invalidate and a following call to get, but since it can piggy-back on an existing load operation that fetched data before invalidate was called, that relationship does not exist.
I started poking around in here to try to fix it, but as @lowasser hinted, it isn’t trivial. The main problems are
This is sufficiently painful that at this point I’m inclined to switch to another library, instead.
@ben-manes thanks for the update about Caffeine.
I am still looking for the Guava team’s perspective on the problem. In particular, would a patch be accepted? what solution categories have been discarded already? What are acceptable drawbacks, if any, for a potential fix?
@lowasser 's comment from 2014 (https://github.com/google/guava/issues/1881#issuecomment-67080198) suggests a patch would be welcome, but there was also a concern about value-in-flight invalidation (https://github.com/google/guava/issues/1881#issuecomment-67076595). Of course, both are couple years old, so they not necessarily describe current state.