[JIRA] Created: (CAY-957) Deadlock in nested contexts

From: Andrus Adamchik (JIRA) ("Andrus)
Date: Wed Jan 09 2008 - 07:59:33 EST

  • Next message: Andrus Adamchik: "Re: Separating mac modeler code"

    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;
                    }

            ..verride
                    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 org.apache.cayenne.event.DispatchQueu..899e9 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 org.apache.cayenne.access.ObjectStor..b9b03 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.
    



    This archive was generated by hypermail 2.0.0 : Wed Jan 09 2008 - 08:00:00 EST