Details
-
Type:
Bug
-
Status: Open
-
Priority:
Major
-
Resolution: Unresolved
-
Affects Version/s: 0.9
-
Fix Version/s: None
-
Component/s: CACHE
-
Labels:None
Description
We have observed a problem using spring for OSCache. This issue happens when a thread inserts data into the cache while an other thread is handling a needsRefreshException.
Consider the following example with 2 thread (th1, th2);
At time t = 0, th1 wants to get some data from the cache. The method protected Object onGetFromCache(Serializable key, CachingModel model) from the OsCacheFacade is called. A Needs refresh exception is thrown, therefore th1 calls cacheManager.cancelUpdate(newKey);
At time t = 1, th2 wants to get the same data from the cache, a needsRefreshException is thrown.
At time t = 2, th1 has loaded the value and inserts it by calling onPutInCache.
At time t = 3, th2 handles the needsRefreshException and calls cacheManager.cancelUpdate(newKey);
The first problem occurs at time = 2, when th1 performs completeUpdate in EntryUpdateState :
if (state != UPDATE_IN_PROGRESS)
{ throw new IllegalStateException("Cannot complete cache update - current state (" + state + ") is not UPDATE_IN_PROGRESS"); }There will be an exception a time = 3, in method public void cancelUpdate(String key) of the cache, because the state is null : log.error("internal error: expected to get a state from key [" + key + "]");
The solution consists in acquiring a lock on the entry before performing any update. A possible (ugly solution), is to replace :
/**
- @see AbstractCacheProviderFacade#onPutInCache(Serializable, CachingModel,
- Object)
*/
protected void onPutInCache(Serializable key, CachingModel model, Object obj) {
OsCacheCachingModel cachingModel = (OsCacheCachingModel) model;
String newKey = getEntryKey(key);
String[] groups = cachingModel.getGroups();
if (groups == null || groups.length == 0) {
try
} else {
try{ cacheManager.getFromCache(newKey); }
catch(NeedsRefreshException e)
{ cacheManager.putInCache(newKey, obj, groups); } }
}