Deadlock between commitChanges and snapshotsUpdatedForObjects

From: Martin Thelian (martin.thelia..ovo.cc)
Date: Thu May 15 2008 - 11:02:37 EDT

  • Next message: Andrus Adamchik: "Re: Deadlock between commitChanges and snapshotsUpdatedForObjects"

    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:03:29 EDT