jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Stefan Guggisberg (JIRA)" <j...@apache.org>
Subject [jira] Commented: (JCR-1359) Adding nodes from concurrently running sessions cause exceptions
Date Fri, 29 Feb 2008 15:52:51 GMT

    [ https://issues.apache.org/jira/browse/JCR-1359?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12573797#action_12573797
] 

Stefan Guggisberg commented on JCR-1359:
----------------------------------------

it took me a while to figure it out but i guess i finally found the root causes of the 2 aforementioned
exceptions, i.e.

a) javax.jcr.nodetype.ConstraintViolationException: /A/7 needs to be saved as well. 
b) javax.jcr.RepositoryException: /A: unable to update item.: Unable to resolve path for item:
016b885a-64aa-45b9-a990-05cbabb4586f/{http://www.jcp.org/jcr/1.0}primaryType

here's my analysis (based on r632346):

a) happens when 
 - thread 1 is in ItemImpl.save(), somewhere around line 1153, just about calling
   nodeState.getRemovedChildNodeEntries() 
-  thread 2 then calls LocalItemStateManager.stateModified() and updates the underlying 
   local state
-  thread 1 continues and calls nodeState.getRemovedChildNodeEntries(), reporting
   the id of the child node added by thread 2 (transient and local state are not in sync 
   at this moment, i.e. the transient state is temporarily stale)
-  thread 2 then calls SessionItemStateManager.stateModified() and merges the transient
   state with the underlying local state; transient and local state are in sync again
- the result is an exception incorrectly complaining about an unsatisfied dependency 
  (id needs to be saved as well)


b) is more severe, it happens when 
-  thread 1 is in NodeImpl.makePersistent(), somewhere within the synchronized block
   starting at line 933, holding the monitor on the NodeState instance 'persistentState'
-  thread 2 then calls ItemState.pull() (via LocalItemStateManager.stateModified()) and
   waits for the monitor  the NodeState instance before entering NodeState.copy())...
-  thread 1 leaves the synchronized block
-  thread 2 now calls NodeState.copy(), effectively overwriting thread 1's changes in 
   the change log...
-  the result is an exception (unable to resolve path) because the child node entry 
   created by thread 1 was lost



> Adding nodes from concurrently running sessions cause exceptions
> ----------------------------------------------------------------
>
>                 Key: JCR-1359
>                 URL: https://issues.apache.org/jira/browse/JCR-1359
>             Project: Jackrabbit
>          Issue Type: Bug
>          Components: jackrabbit-core
>    Affects Versions: 1.3.3, 1.4, core 1.4.1
>            Reporter: Alexander Nesterov
>            Assignee: Stefan Guggisberg
>            Priority: Critical
>             Fix For: core 1.4.2
>
>
> Exceptions are thrown when trying to add child nodes to one parent node from different
sessions running concurrently. One of the following exceptions is always thrown:
>  * Exception in thread "Thread-8" java.lang.RuntimeException: javax.jcr.nodetype.ConstraintViolationException:
/A/7 needs to be saved as well.
>  * Exception in thread "Thread-8" java.lang.RuntimeException: javax.jcr.RepositoryException:
/A: unable to update item.: Unable to
> resolve path for item: 016b885a-64aa-45b9-a990-05cbabb4586f/{http://www.jcp.org/jcr/1.0}primaryType:
Unable to resolve path for item: 016b885a-64aa-45b9-a990-05cbabb4586f/{http://www.jcp.org/jcr/1.0}primaryType
> According to JCR-584 "Improve handling of concurrent node modifications" the following
scenario "session 1 adds or removes child node 'x', session 2 adds or removes child node 'y'"
should run gracefully, but the following test constantly fails:
> public void testSync() throws Exception
> {
>        Node rootNode = getSession ().getRootNode ();
>        rootNode.addNode ("A");
>        rootNode.save();
>        final Session session1 = getRepository().login (new SimpleCredentials ("userName",
"password".toCharArray()));
>        final Session session2 = getRepository().login (new SimpleCredentials ("userName",
"password".toCharArray()));
>        Thread thread1 = new Thread (new Runnable()
>        {
>                public void run()
>                {
>                        try
>                        {
>                                addNodes ("A", session1, 0);
>                        }
>                        catch (RepositoryException ex)
>                        {
>                                throw new RuntimeException (ex);
>                        }
>                }
>        });
>        Thread thread2 = new Thread (new Runnable()
>        {
>                public void run()
>                {
>                        try
>                        {
>                                addNodes ("A", session2, 1001);
>                        }
>                        catch (RepositoryException ex)
>                        {
>                                throw new RuntimeException (ex);
>                        }
>                }
>        });
>        thread1.start();
>        thread2.start();
>        thread1.join();
>        thread2.join();
> }
> private void addNodes (String parentName, Session session, int startIndex)
>        throws RepositoryException
> {
>        Node parentNode = session.getRootNode().getNode (parentName);
>        for (int i = startIndex; i < startIndex + 100; i++)
>        {
>                String name = Integer.toString (i);
>                parentNode.addNode (name);
>                parentNode.save();
>        }
> }
> BTW: exceptions were also thrown when I tried to add nodes from one thread and remove
some of them from another one. Each thread used it's own session, each node had unique name.

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


Mime
View raw message