Deadlock in nested contexts
---------------------------

                 Key: CAY-957
                 URL: https://issues.apache.org/cayenne/browse/CAY-957
             Project: Cayenne
          Issue Type: Bug
          Components: Cayenne Core Library
    Affects Versions: 1.2 [STABLE], 2.0 [STABLE], 3.0
            Reporter: Andrus Adamchik
            Assignee: Andrus Adamchik
             Fix For: 3.0


There is a deadlock condition when two peer nested contexts commit 
simultaneously. Here is a small test case:

package org.test;

import java.util.Date;
import java.util.List;
import java.util.Random;

import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.query.EJBQLQuery;

public class Main {

        public static void main(String[] args) {
                DataContext parent = DataContext.createDataContext();

                parent.performGenericQuery(new EJBQLQuery("delete from 
Artist"));

                for (int i = 0; i < 300; i++) {
                        Artist a = parent.newObject(Artist.class);
                        a.setArtistName("X" + i);
                        a.setDateOfBirth(new Date());
                }

                parent.commitChanges();

                Random rnd = new Random(System.currentTimeMillis());
                for (int i = 0; i < 2; i++) {
                        new UpdateThread(parent.createChildDataContext(), 
rnd).start();
                }

                synchronized (parent) {
                        try {
                                parent.wait();
                        } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                }

        }

        static class UpdateThread extends Thread {
                protected DataContext context;
                protected Random rnd;

                UpdateThread(DataContext context, Random rnd) {
                        super("UpdateThread-" + context.hashCode());
                        setDaemon(true);
                        this.context = context;
                        this.rnd = rnd;
                }

                @Override
                public void run() {

                        List<Artist> artists = context.performQuery(new 
EJBQLQuery(
                                        "select a FROM Artist a"));

                        for (int i = 0; i < 1000; i++) {

                                for (int j = 0; j < 5; j++) {
                                        int index = rnd.nextInt(artists.size());
                                        Artist a = artists.get(index);
                                        a.setArtistName("Y" + rnd.nextInt());
                                }

                                context.commitChanges();
                                System.out.println(getId() + ": " + i);
                        }
                }
        }
}


It deadlocks almost immediately with only two threads... Here is the stacks 
from Jconsole:

Name: UpdateThread-9684455
State: BLOCKED on [EMAIL PROTECTED] owned by: UpdateThread-10872036
Total blocked: 7  Total waited: 1

Stack trace: 
org.apache.cayenne.event.DispatchQueue.dispatchEvent(DispatchQueue.java:54)
org.apache.cayenne.event.EventManager.dispatchEvent(EventManager.java:348)
org.apache.cayenne.event.EventManager.postEvent(EventManager.java:319)
org.apache.cayenne.access.DataContext.fireDataChannelChanged(DataContext.java:1457)
org.apache.cayenne.access.DataContext.onContextFlush(DataContext.java:1121)
org.apache.cayenne.access.DataContext.onSync(DataContext.java:1102)
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:1160)
org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:1073)
org.test.Main$UpdateThread.run(Main.java:66)



Name: UpdateThread-10872036
State: BLOCKED on [EMAIL PROTECTED] owned by: UpdateThread-9684455
Total blocked: 9  Total waited: 0

Stack trace: 
org.apache.cayenne.access.DataContextMergeHandler.graphChanged(DataContextMergeHandler.java:104)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:585)
org.apache.cayenne.util.Invocation.fire(Invocation.java:204)
org.apache.cayenne.event.EventManager$Dispatch.fire(EventManager.java:409)
org.apache.cayenne.event.DispatchQueue.dispatchEvent(DispatchQueue.java:162)
org.apache.cayenne.event.DispatchQueue.dispatchEvent(DispatchQueue.java:58)
org.apache.cayenne.event.EventManager.dispatchEvent(EventManager.java:348)
org.apache.cayenne.event.EventManager.postEvent(EventManager.java:319)
org.apache.cayenne.access.DataContext.fireDataChannelChanged(DataContext.java:1457)
org.apache.cayenne.access.DataContext.onContextFlush(DataContext.java:1121)
org.apache.cayenne.access.DataContext.onSync(DataContext.java:1102)
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:1160)
org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:1073)
org.test.Main$UpdateThread.run(Main.java:66)




-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to