Re: Deadlock between commitChanges and snapshotsUpdatedForObjects

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Thu May 15 2008 - 11:43:39 EDT

  • Next message: Martin Thelian: "Re: Deadlock between commitChanges and snapshotsUpdatedForObjects"

    Hmm... I don't see a deadlock, just a contention with other threads
    waiting for "userDataBeanMessageListener-5" to finish commit. So does
    it result in slowness or a complete deadlock?

    (there are known issues with nested contexts [1], but there weren't
    any with the top-level contexts in a while).

    Andrus

    [1] https://issues.apache.org/cayenne/browse/CAY-957

    On May 15, 2008, at 11:02 AM, Martin Thelian wrote:

    > Hi,
    >
    > in our application we are using cayenne 1.2.4 and have the problem
    > that
    > we run into a deadlock if two users try to update their data in
    > parallel. I've analyzed the thread-dumps and this are the threads that
    > are involved:
    >
    > ------------------------------------------
    > "userDataBeanMessageListener-5" prio=1 tid=0x08f85f58 nid=0x53d3
    > runnable [0x83cf5000..0x83cf6e30]
    > at java.net.SocketInputStream.socketRead0(Native Method)
    > at java.net.SocketInputStream.read(SocketInputStream.java:129)
    > at java.io.BufferedInputStream.fill(BufferedInputStream.java:
    > 218)
    > at java.io.BufferedInputStream.read(BufferedInputStream.java:
    > 235)
    > - locked <0x9303e150> (a java.io.BufferedInputStream)
    > at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:256)
    > at
    > org
    > .postgresql
    > .core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1163)
    > at
    > org
    > .postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:
    > 347)
    > - locked <0x93027df8> (a
    > org.postgresql.core.v3.QueryExecutorImpl)
    > at
    > org
    > .postgresql
    > .jdbc2
    > .AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2574)
    > at
    > org
    > .objectstyle
    > .cayenne.access.jdbc.BatchAction.runAsBatch(BatchAction.java:164)
    > at
    > org
    > .objectstyle
    > .cayenne.access.jdbc.BatchAction.performAction(BatchAction.java:114)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataNodeQueryAction.runQuery(DataNodeQueryAction.java:95)
    > at
    > org.objectstyle.cayenne.access.DataNode.performQueries(DataNode.java:
    > 309)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataDomainFlushAction.runQueries(DataDomainFlushAction.java:
    > 255)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataDomainFlushAction.flush(DataDomainFlushAction.java:177)
    > - locked <0x92f78110> (a
    > org.objectstyle.cayenne.access.DataRowStore)
    > at
    > org
    > .objectstyle.cayenne.access.DataDomain.onSyncFlush(DataDomain.java:
    > 846)
    > at
    > org.objectstyle.cayenne.access.DataDomain
    > $2.transform(DataDomain.java:817)
    > at
    > org
    > .objectstyle
    > .cayenne.access.DataDomain.runInTransaction(DataDomain.java:862)
    > at
    > org.objectstyle.cayenne.access.DataDomain.onSync(DataDomain.java:814)
    > at
    > org
    > .objectstyle
    > .cayenne.access.DataContext.flushToParent(DataContext.java:1270)
    > - locked <0x8eff78d8> (a
    > org.objectstyle.cayenne.access.ObjectStore)
    > at
    > org
    > .objectstyle
    > .cayenne.access.DataContext.commitChanges(DataContext.java:1174)
    > at
    > cc
    > .lovo
    > .data
    > .cayenne.CayenneUserDataBean.setUserData(CayenneUserDataBean.java:851)
    > at
    > cc
    > .lovo
    > .data
    > .cayenne.CayenneUserDataBean.createUser(CayenneUserDataBean.java:627)
    > [...]
    >
    > "userDataBeanMessageListener-1" prio=1 tid=0x08f81cd0 nid=0x53cf
    > waiting
    > for monitor entry [0x83ef9000..0x83efb030]
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataRowStore.snapshotsUpdatedForObjects(DataRowStore.java:272)
    > - waiting to lock <0x92f78110> (a
    > org.objectstyle.cayenne.access.DataRowStore)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.ObjectResolver.objectsFromDataRows(ObjectResolver.java:157)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access
    > .ObjectResolver.synchronizedObjectsFromDataRows(ObjectResolver.java:
    > 133)
    > - locked <0x8eff7dc8> (a
    > org.objectstyle.cayenne.access.ObjectStore)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access
    > .DataDomainQueryAction
    > .interceptObjectConversion(DataDomainQueryAction.java:355)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataDomainQueryAction.execute(DataDomainQueryAction.java:152)
    > at
    > org.objectstyle.cayenne.access.DataDomain.onQuery(DataDomain.java:782)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .util
    > .ObjectContextQueryAction.runQuery(ObjectContextQueryAction.java:253)
    > at
    > org
    > .objectstyle
    > .cayenne
    > .access.DataContextQueryAction.execute(DataContextQueryAction.java:90)
    > at
    > org.objectstyle.cayenne.access.DataContext.onQuery(DataContext.java:
    > 1431)
    > at
    > org
    > .objectstyle
    > .cayenne.access.DataContext.performQuery(DataContext.java:1420)
    > at
    > cc
    > .lovo
    > .data
    > .cayenne.common.CayenneDataBean.getMBForLanCou(CayenneDataBean.java:
    > 156)
    > at
    > cc
    > .lovo
    > .data
    > .cayenne.common.CayenneDataBean.getCurrLocale(CayenneDataBean.java:
    > 177)
    > at
    > cc
    > .lovo
    > .data
    > .cayenne.CayenneUserDataBean.getProfileData(CayenneUserDataBean.java:
    > 199)
    > at
    > cc
    > .lovo
    > .data.cayenne.CayenneUserDataBean.getUser(CayenneUserDataBean.java:
    > 147)
    > [...]
    >
    > "EventDispatchThread-4" daemon prio=1 tid=0x85b9e280 nid=0x5488
    > waiting
    > for monitor entry [0x7d428000..0x7d429030]
    > at
    > org
    > .objectstyle
    > .cayenne.access.ObjectStore.processSnapshotEvent(ObjectStore.java:813)
    > - waiting to lock <0x8eff78d8> (a
    > org.objectstyle.cayenne.access.ObjectStore)
    > at
    > org
    > .objectstyle
    > .cayenne.access.ObjectStore.snapshotsChanged(ObjectStore.java:804)
    > at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown
    > Source)
    > at
    > sun
    > .reflect
    > .DelegatingMethodAccessorImpl
    > .invoke(DelegatingMethodAccessorImpl.java:25)
    > at java.lang.reflect.Method.invoke(Method.java:585)
    > at
    > org.objectstyle.cayenne.util.Invocation.fire(Invocation.java:240)
    > at
    > org.objectstyle.cayenne.event.EventManager
    > $InvocationDispatch.fire(EventManager.java:452)
    > at
    > org.objectstyle.cayenne.event.EventManager
    > $DispatchThread.run(EventManager.java:499)
    >
    > ------------------------------------------
    >
    > The thread "userDataBeanMessageListener-5" seem to lock the whole
    > DataRowCache via a call to function
    > org
    > .objectstyle
    > .cayenne
    > .access.DataDomainFlushAction.flush(DataDomainFlushAction.java:177):
    >
    > |> synchronized (context.getObjectStore().getDataRowCache()) {
    > |> [...]
    > |> runQueries();
    > |> [...]
    > |> }
    >
    > but itself seems to wait via Socket-read for the thread
    > userDataBeanMessageListener-1 to finishes its DB-query. The Problem is
    > that this thread also tries to enter a sync block in the DataRowStore
    > but blocks.
    >
    > The relevant code in
    > org
    > .objectstyle
    > .cayenne
    > .access.DataRowStore.snapshotsUpdatedForObjects(DataRowStore.java:
    > 272):
    >
    > |> void snapshotsUpdatedForObjects(List objects, List snapshots,
    > boolean refresh) {
    > |> [...]
    > |>
    > |> synchronized (this) {
    > |> [...]
    >
    >
    > A third thread also seems to try to enter a synchronized block in
    > |> synchronized void processSnapshotEvent(SnapshotEvent event) {
    > |> [...]
    > |> }
    >
    >
    > Any hints how we can get around this problem?
    >
    > Thanks,
    > Martin
    >



    This archive was generated by hypermail 2.0.0 : Thu May 15 2008 - 11:44:10 EDT