This problem has been posted many times before. But in this topic i am not asking for a solution for this IdentityLock exception, but would like to know why actually this occurs and whether there is a better way to deal with this. Let me mention the scenario, where i see this exception:
We have a J2EE application in JBoss-3.2.3 which uses Hibernate-2.1.3 as a MBean and JBossCache1.2 as the second level cache. Pessimistic locking is used in JBossCache. We frequently stumbled across exceptions similar to the following:
Caused by: net.sf.hibernate.cache.CacheException: org.jboss.cache.lock.TimeoutException: write lock for //com/dbdata/core/processingengine/hibernateobject/CrExecutionList/com.dbdata.core.processingengine.hibernateobject.CrExecutionListId@24da09[processingEngineId=1904,processingEngineVersionId=1,executionListId=23] could not be acquired after 25000 ms. Lock map ownership Read lock owners:  Write lock owner: <null>:116 (caller=<null>:117) at net.sf.hibernate.cache.TreeCache.put(TreeCache.java:70) at net.sf.hibernate.cache.TransactionalCache.put(TransactionalCache.java:42) at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2203) at net.sf.hibernate.loader.Loader.doQuery(Loader.java:293) at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:186) at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:968) at net.sf.hibernate.loader.Loader.loadCollection(Loader.java:943) at net.sf.hibernate.loader.OneToManyLoader.initialize(OneToManyLoader.java:93) at net.sf.hibernate.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:284) at net.sf.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:3259) at net.sf.hibernate.collection.PersistentCollection.initialize(PersistentCollection.java:195) ... 103 more Caused by: org.jboss.cache.lock.TimeoutException: write lock for //com/dbdata/core/processingengine/hibernateobject/CrExecutionList/com.dbdata.core.processingengine.hibernateobject.CrExecutionListId@24da09[processingEngineId=1904,processingEngineVersionId=1,executionListId=23] could not be acquired after 25000 ms. Lock map ownership Read lock owners:  Write lock owner: <null>:116 (caller=<null>:117) at org.jboss.cache.lock.IdentityLock.acquireWriteLock(IdentityLock.java:179) at org.jboss.cache.Node.acquireWriteLock(Node.java:424) at org.jboss.cache.Node.acquire(Node.java:401) at org.jboss.cache.interceptors.LockInterceptor.lock(LockInterceptor.java:184) at org.jboss.cache.interceptors.LockInterceptor.invoke(LockInterceptor.java:134) at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:40) at org.jboss.cache.interceptors.CreateIfNotExistsInterceptor.invoke(CreateIfNotExistsInterceptor.java:47) at org.jboss.cache.TreeCache.invokeMethod(TreeCache.java:3078) at org.jboss.cache.TreeCache.put(TreeCache.java:1758) at net.sf.hibernate.cache.TreeCache.put(TreeCache.java:67)
What i got to know is that, when a hibernateobject is being put into the cache a lock is acquired on the same with reference to transaction id. If some other user tries to access the same object(or even the hierarchy of the node) from some other transaction, then he will have to wait for a time of "LockAcquisitionTimeout" which is specified while configuring the cache. If even after this wait time the lock is not released by the previous transaction which is holding the lock(the lock will be released only when the transaction commits/rollbacks), then the CacheException is thrown and as a result the application crashes.
Here's my question regarding this approach:
- Cant the above situation be handled in a different way by JBossCache. Something like the following:
When JBossCache sees that a lock is NOT released even after the lockAcquisitionTimeout time, it will maintain a reference of the node on which the timeout occured and wont throw any exception(may be just log a message). And when the transaction which held the lock on this node completes, JBossCache will just evict this node(for which the other transaction was trying to obtain a lock) from the cache, so that the node contents are not stale.
The next time this node is looked up, it wont be found in the cache and database trip would be required, which is just a bit of performance issue, but there wont be any application crashes occuring because of exception being thrown on not being able to obtain a lock.
Please correct me if i am wrong on this issue.
Currently, we are facing this issue very frequently in multi user scenario to such an extent that the application is almost not suitable for going into production in multi user scenario. Disabling second level cache solves the issue but this is obviously not an option for us since the application heavily operates on hibernateobjects and hence performance is also a issue.
Hope to see some answer to this question.