Description
Hi,
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