Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 331921

Summary: deadlock uow commit and query using joins
Product: z_Archived Reporter: Chris Delahunt <christopher.delahunt>
Component: EclipselinkAssignee: Nobody - feel free to take it <nobody>
Status: RESOLVED FIXED QA Contact:
Severity: critical    
Priority: P3 CC: douglas.clarke
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
proposed fix
none
revised fix
none
Core test for the fix none

Description Chris Delahunt CLA 2010-12-06 11:12:23 EST
A deadlock can occur in an object model where classA references classB which references classC, and classC has no relationship mappings.  Thread1 attempts to refresh classB and uses joining to bring in classC.  Thread2 attempts to modify classA and classC, and sets classA to reference a classB being read in threadA.
1) Thread1 gets deferred lock on ClassB
2) Thread2 gets required locks on classA+classC for updates
3) Thread1 attempts to get active lock on classC, but has to wait as it is held by thread2
4) Thread2 updates, commits, and during the merge tries to get a lock on classB.  This causes it to transition to deferred locks.
4b) thread2 attempts to release its deferred lock, causing it to waiting on threadB - a deadlock. 

Threaddump from such a situation will look similiar to: 
Thread1:
java.lang.Thread.State: WAITING (on object monitor)
   at java.lang.Object.wait(Native Method)
   - waiting on <0x000000074eb19a00> (a org.eclipse.persistence.internal.helper.ConcurrencyManager)
   at java.lang.Object.wait(Object.java:485)
   at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquire(ConcurrencyManager.java:93)
   - locked <0x000000074eb19a00> (a org.eclipse.persistence.internal.helper.ConcurrencyManager)
   at org.eclipse.persistence.internal.identitymaps.CacheKey.acquire(CacheKey.java:113)
   at org.eclipse.persistence.internal.identitymaps.AbstractIdentityMap.acquireLock(AbstractIdentityMap.java:107)
   at org.eclipse.persistence.internal.identitymaps.IdentityMapManager.acquireLock(IdentityMapManager.java:127)
   at org.eclipse.persistence.internal.sessions.IdentityMapAccessor.acquireLock(IdentityMapAccessor.java:92)
   at org.eclipse.persistence.internal.sessions.IdentityMapAccessor.acquireLock(IdentityMapAccessor.java:83)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:698)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:504)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:454)
   at org.eclipse.persistence.mappings.OneToOneMapping.valueFromRowInternalWithJoin(OneToOneMapping.java:1595)
   at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:1737)
   at org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1283)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:342)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:717)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:504)
   at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectsInto(ObjectBuilder.java:910)
   at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:423)
   at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1076)
   at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:740)
   at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1036)
   at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:380)
   at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:2392)
Thread2:
java.lang.Thread.State: TIMED_WAITING (sleeping)
   at java.lang.Thread.sleep(Native Method)
   at org.eclipse.persistence.internal.helper.ConcurrencyManager.releaseDeferredLock(ConcurrencyManager.java:464)
   at org.eclipse.persistence.internal.identitymaps.CacheKey.releaseDeferredLock(CacheKey.java:348)
   at org.eclipse.persistence.internal.helper.WriteLockManager.releaseAllAcquiredLocks(WriteLockManager.java:467)
   at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeChangesIntoParent(UnitOfWorkImpl.java:3321)
   at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeClonesAfterCompletion(UnitOfWorkImpl.java:3424)
   at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAfterWriteChanges(UnitOfWorkImpl.java:1245)
   at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commit(UnitOfWorkImpl.java:1081) 

Multiple threads may look like thread 1, as queries on other threads will end up having to wait for these two threads to release their locks.
Comment 1 Chris Delahunt CLA 2010-12-06 11:33:05 EST
Created attachment 184627 [details]
proposed fix
Comment 2 Chris Delahunt CLA 2010-12-06 12:32:49 EST
Created attachment 184637 [details]
revised fix
Comment 3 Chris Delahunt CLA 2010-12-09 14:38:35 EST
Created attachment 184890 [details]
Core test for the fix
Comment 4 Chris Delahunt CLA 2010-12-09 15:42:15 EST
fix was checked into 2.1.2 revision 8635
fix and test patch was checked into 2.2 revision 8679
Comment 5 Eclipse Webmaster CLA 2022-06-09 10:24:10 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink