Author: cbegin Date: Sat Jan 21 18:31:59 2006 New Revision: 371170 URL: http://svn.apache.org/viewcvs?rev=371170&view=rev Log: Fixed IBATIS-223 Thread deadlock due to CacheModel.flush() (Sven's fix)
Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/cache/CacheModel.java ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/CachingStatement.java Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/cache/CacheModel.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/cache/CacheModel.java?rev=371170&r1=371169&r2=371170&view=diff ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/cache/CacheModel.java (original) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/cache/CacheModel.java Sat Jan 21 18:31:59 2006 @@ -24,17 +24,14 @@ import java.util.*; /** - * + * Wrapper for Caches. */ public class CacheModel implements ExecuteListener { - - private static final Map lockMap = new HashMap(); /** * This is used to represent null objects that are returned from the cache so * that they can be cached, too. */ public static final Object NULL_OBJECT = new Object(); - private final Object STATS_LOCK = new Object(); private int requests = 0; private int hits = 0; @@ -237,12 +234,9 @@ * Clears the cache */ public void flush() { - lastFlush = System.currentTimeMillis(); - // use the controller's key - CacheKey key = new CacheKey(); - key.update(controller); - synchronized (getLock(key)) { + synchronized (this) { controller.flush(this); + lastFlush = System.currentTimeMillis(); } } @@ -255,39 +249,32 @@ * @return The cached object (or null) */ public Object getObject(CacheKey key) { + Object value = null; synchronized (this) { if (flushInterval != NO_FLUSH_INTERVAL && System.currentTimeMillis() - lastFlush > flushInterval) { flush(); } - } - Object value = null; - synchronized (getLock(key)) { value = controller.getObject(this, key); - } - - if (serialize && !readOnly && (value != NULL_OBJECT && value != null)) { - try { - ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value); - ObjectInputStream ois = new ObjectInputStream(bis); - value = ois.readObject(); - ois.close(); - } catch (Exception e) { - throw new NestedRuntimeException("Error caching serializable object. Be sure you're not attempting to use " + - "a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e); + if (serialize && !readOnly && + (value != NULL_OBJECT && value != null)) { + try { + ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value); + ObjectInputStream ois = new ObjectInputStream(bis); + value = ois.readObject(); + ois.close(); + } catch (Exception e) { + throw new NestedRuntimeException("Error caching serializable object. Be sure you're not attempting to use " + + "a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e); + } } - } - - synchronized (STATS_LOCK) { requests++; if (value != null) { hits++; } } - return value; - } /** @@ -297,39 +284,21 @@ * @param value The object to be cached */ public void putObject(CacheKey key, Object value) { - if (null == value) value = NULL_OBJECT; - if (serialize && !readOnly && value != NULL_OBJECT) { - try { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(value); - oos.flush(); - oos.close(); - value = bos.toByteArray(); - } catch (IOException e) { - throw new NestedRuntimeException("Error caching serializable object. Cause: " + e, e); + if (null == value) value = NULL_OBJECT; + synchronized ( this ) { + if (serialize && !readOnly && value != NULL_OBJECT) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(value); + oos.flush(); + oos.close(); + value = bos.toByteArray(); + } catch (IOException e) { + throw new NestedRuntimeException("Error caching serializable object. Cause: " + e, e); + } } - } - synchronized (getLock(key)) { controller.putObject(this, key, value); } } - - /** - * OK, honestly, i have no idea what this does. - * @param key - * @return - */ - public synchronized final Object getLock(CacheKey key) { - int controllerId = System.identityHashCode(controller); - int keyHash = key.hashCode(); - Integer lockKey = new Integer(29 * controllerId + keyHash); - Object lock = lockMap.get(lockKey); - if (lock == null) { - lock = lockKey; //might as well use the same object - lockMap.put(lockKey, lock); - } - return lock; - } - } Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/CachingStatement.java URL: http://svn.apache.org/viewcvs/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/CachingStatement.java?rev=371170&r1=371169&r2=371170&view=diff ============================================================================== --- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/CachingStatement.java (original) +++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/CachingStatement.java Sat Jan 21 18:31:59 2006 @@ -76,10 +76,8 @@ // This was cached, but null object = null; }else if (object == null) { - synchronized (cacheModel.getLock(cacheKey)) { - object = statement.executeQueryForObject(request, trans, parameterObject, resultObject); - cacheModel.putObject(cacheKey, object); - } + object = statement.executeQueryForObject(request, trans, parameterObject, resultObject); + cacheModel.putObject(cacheKey, object); } return object; } @@ -96,10 +94,8 @@ // The cached object was null list = null; }else if (listAsObject == null) { - synchronized (cacheModel.getLock(cacheKey)) { - list = statement.executeQueryForList(request, trans, parameterObject, skipResults, maxResults); - cacheModel.putObject(cacheKey, list); - } + list = statement.executeQueryForList(request, trans, parameterObject, skipResults, maxResults); + cacheModel.putObject(cacheKey, list); }else{ list = (List) listAsObject; }