Author: tv Date: Fri Nov 9 20:48:18 2012 New Revision: 1407624 URL: http://svn.apache.org/viewvc?rev=1407624&view=rev Log: Fix JCS-73: Concurrent cache access causes values loss - added missing synchronization
Modified: commons/proper/jcs/trunk/src/changes/changes.xml commons/proper/jcs/trunk/src/java/org/apache/jcs/access/GroupCacheAccess.java commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/control/CompositeCache.java commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java Modified: commons/proper/jcs/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/src/changes/changes.xml?rev=1407624&r1=1407623&r2=1407624&view=diff ============================================================================== --- commons/proper/jcs/trunk/src/changes/changes.xml (original) +++ commons/proper/jcs/trunk/src/changes/changes.xml Fri Nov 9 20:48:18 2012 @@ -20,6 +20,9 @@ </properties> <body> <release version="2.0" date="unreleased" description="JDK 1.5 based major release"> + <action dev="tv" type="fix" issue="JCS-73" due-to="Alexander Kleymenov"> + Concurrent cache access causes values loss. + </action> <action dev="tv" type="fix" issue="JCS-77" due-to="Matt Morrisson"> NullPointerException thrown by IndexedDiskCache if IndexedDisk calls fail to initialize. Modified: commons/proper/jcs/trunk/src/java/org/apache/jcs/access/GroupCacheAccess.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/src/java/org/apache/jcs/access/GroupCacheAccess.java?rev=1407624&r1=1407623&r2=1407624&view=diff ============================================================================== --- commons/proper/jcs/trunk/src/java/org/apache/jcs/access/GroupCacheAccess.java (original) +++ commons/proper/jcs/trunk/src/java/org/apache/jcs/access/GroupCacheAccess.java Fri Nov 9 20:48:18 2012 @@ -162,9 +162,6 @@ public class GroupCacheAccess<K extends throw new InvalidArgumentException( "Value must not be null" ); } - // unbind object first if any. - remove( name, groupName ); - // Create the element and update. This may throw an IOException which // should be wrapped by cache access. try Modified: commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/control/CompositeCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/control/CompositeCache.java?rev=1407624&r1=1407623&r2=1407624&view=diff ============================================================================== --- commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/control/CompositeCache.java (original) +++ commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/control/CompositeCache.java Fri Nov 9 20:48:18 2012 @@ -211,7 +211,7 @@ public class CompositeCache<K extends Se if ( log.isDebugEnabled() ) { - log.debug( "Updating memory cache" ); + log.debug( "Updating memory cache " + cacheElement.getKey() ); } synchronized ( this ) @@ -466,121 +466,124 @@ public class CompositeCache<K extends Se log.debug( "get: key = " + key + ", localOnly = " + localOnly ); } - try + synchronized (this) { - // First look in memory cache - element = memCache.get( key ); - - if ( element != null ) + try { - // Found in memory cache - if ( isExpired( element ) ) + // First look in memory cache + element = memCache.get( key ); + + if ( element != null ) { - if ( log.isDebugEnabled() ) + // Found in memory cache + if ( isExpired( element ) ) { - log.debug( cacheName + " - Memory cache hit, but element expired" ); - } + if ( log.isDebugEnabled() ) + { + log.debug( cacheName + " - Memory cache hit, but element expired" ); + } - missCountExpired++; + missCountExpired++; - remove( key ); + remove( key ); - element = null; - } - else - { - if ( log.isDebugEnabled() ) + element = null; + } + else { - log.debug( cacheName + " - Memory cache hit" ); + if ( log.isDebugEnabled() ) + { + log.debug( cacheName + " - Memory cache hit" ); + } + + // Update counters + hitCountRam++; } - // Update counters - hitCountRam++; + found = true; } - - found = true; - } - else - { - // Item not found in memory. If local invocation look in aux - // caches, even if not local look in disk auxiliaries - - for ( int i = 0; i < auxCaches.length; i++ ) + else { - AuxiliaryCache<K, V> aux = auxCaches[i]; + // Item not found in memory. If local invocation look in aux + // caches, even if not local look in disk auxiliaries - if ( aux != null ) + for ( int i = 0; i < auxCaches.length; i++ ) { - CacheType cacheType = aux.getCacheType(); + AuxiliaryCache<K, V> aux = auxCaches[i]; - if ( !localOnly || cacheType == CacheType.DISK_CACHE ) + if ( aux != null ) { - if ( log.isDebugEnabled() ) - { - log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: " - + cacheType ); - } + CacheType cacheType = aux.getCacheType(); - try - { - element = aux.get( key ); - } - catch ( IOException e ) - { - log.error( "Error getting from aux", e ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Got CacheElement: " + element ); - } - - // Item found in one of the auxiliary caches. - if ( element != null ) - { - if ( isExpired( element ) ) + if ( !localOnly || cacheType == CacheType.DISK_CACHE ) { if ( log.isDebugEnabled() ) { - log.debug( cacheName + " - Aux cache[" + i + "] hit, but element expired." ); + log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: " + + cacheType ); } - missCountExpired++; - - // This will tell the remotes to remove the item - // based on the element's expiration policy. The elements attributes - // associated with the item when it created govern its behavior - // everywhere. - remove( key ); + try + { + element = aux.get( key ); + } + catch ( IOException e ) + { + log.error( "Error getting from aux", e ); + } + } - element = null; + if ( log.isDebugEnabled() ) + { + log.debug( "Got CacheElement: " + element ); } - else + + // Item found in one of the auxiliary caches. + if ( element != null ) { - if ( log.isDebugEnabled() ) + if ( isExpired( element ) ) { - log.debug( cacheName + " - Aux cache[" + i + "] hit" ); - } + if ( log.isDebugEnabled() ) + { + log.debug( cacheName + " - Aux cache[" + i + "] hit, but element expired." ); + } + + missCountExpired++; + + // This will tell the remotes to remove the item + // based on the element's expiration policy. The elements attributes + // associated with the item when it created govern its behavior + // everywhere. + remove( key ); - // Update counters - hitCountAux++; - auxHitCountByIndex[i]++; + element = null; + } + else + { + if ( log.isDebugEnabled() ) + { + log.debug( cacheName + " - Aux cache[" + i + "] hit" ); + } + + // Update counters + hitCountAux++; + auxHitCountByIndex[i]++; - copyAuxiliaryRetrievedItemToMemory( element ); - } + copyAuxiliaryRetrievedItemToMemory( element ); + } - found = true; + found = true; - break; + break; + } } } } } - } - catch ( Exception e ) - { - log.error( "Problem encountered getting element.", e ); + catch ( Exception e ) + { + log.error( "Problem encountered getting element.", e ); + } } if ( !found ) Modified: commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java URL: http://svn.apache.org/viewvc/commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java?rev=1407624&r1=1407623&r2=1407624&view=diff ============================================================================== --- commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java (original) +++ commons/proper/jcs/trunk/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java Fri Nov 9 20:48:18 2012 @@ -29,7 +29,7 @@ import org.apache.jcs.engine.memory.util /** * A fast reference management system. The least recently used items move to the end of the list and * get spooled to disk if the cache hub is configured to use a disk cache. Most of the cache - * bottelnecks are in IO. There are no io bottlenecks here, it's all about processing power. + * bottlenecks are in IO. There are no io bottlenecks here, it's all about processing power. * <p> * Even though there are only a few adjustments necessary to maintain the double linked list, we * might want to find a more efficient memory manager for large cache regions.