jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Jervis Liu (JIRA)" <j...@apache.org>
Subject [jira] Created: (JCR-2269) Possible concurrency bug with Workspace.copy()
Date Fri, 21 Aug 2009 09:19:14 GMT
Possible concurrency bug with Workspace.copy() 

                 Key: JCR-2269
                 URL: https://issues.apache.org/jira/browse/JCR-2269
             Project: Jackrabbit Content Repository
          Issue Type: Bug
          Components: jackrabbit-core
    Affects Versions: 1.6.0
            Reporter: Jervis Liu


Enclosed below is a test case that can be used to reproduce a
concurrency bug. This test case uses two con-current threads to
execute Workspace.copy() to copy a node to same destination. The
parent node has set its allowSameNameSiblings to false. According to
the javadoc of Workspace.copy(String srcAbsPath, String destAbsPath) :
"This method copies the node at srcAbsPath to the new location at
destAbsPath. If successful, the change is persisted immediately, there
is no need to call save.".  "An ItemExistException is thrown if a
property already exists at destAbsPath or a node already exist there,
and same name siblings are not allowed. "

However in reality this is not the case.  The test case can end up
with two child nodes with same names. Please note, not every run can
reproduce the problem, but generally I can get the problem within 3 to
10 iterations. I also got an InvalidItemStateException once (only
once).  Can someone kindly help to confirm if this is a bug in
Jackrabbit or maybe I am using JackRabbit in a wrong way? The test
case has been tested on Jackrabbit 1.6 branch
(http://svn.apache.org/repos/asf/jackrabbit/tags/1.6.0), Windows
Vista, JDK 1.5.0_14.

The test case is also attached for your convenience.

Jervis Liu

package org.apache.jackrabbit.core;

import org.apache.jackrabbit.test.AbstractJCRTest;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.NodeIterator;
import java.util.Random;
import java.util.ArrayList;
import java.util.Iterator;
import javax.jcr.nodetype.NodeType;

import org.apache.jackrabbit.test.NotExecutableException;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.NodeTypeManager;

public class ConcurrentCopyTest extends AbstractJCRTest {

    private static final int NUM_ITERATIONS = 40;
    private static final int NUM_SESSIONS = 2;

    String sourcePath;
    String destPath;

    public void testConcurrentCopy() throws Exception {
        for (int n = 0; n < NUM_ITERATIONS; n++) {
            System.out.println("---Iteration---- " + n);

            // clean up testRoot first
            if (testRootNode.hasNode("ConcurrentCopyTestNode")) {
                Node testNode = testRootNode.getNode("ConcurrentCopyTestNode");
                System.out.println("---old node removed---");

            // create a parent node where allowSameNameSiblings is set to false
            Node snsfNode = testRootNode.addNode("ConcurrentCopyTestNode",
            sourcePath = snsfNode.getPath();
            destPath = sourcePath + "/" + "CopiedFromConcurrentCopyTestNode";
            System.out.println("---sourcePath-----------------" + sourcePath);
            System.out.println("---destPath-----------------" + destPath);

            // firstly we verify it works with single thread.
            Session rootSession = helper.getSuperuserSession();
            rootSession.getWorkspace().copy(sourcePath, destPath + "test");

            // copy again to same destPath, expect an ItemExistsException
            try {
                rootSession.getWorkspace().copy(sourcePath, destPath + "test");
                fail("Node exists below '" + destPath + "'. Test should fail.");
            } catch (ItemExistsException e) {

            Thread[] threads = new Thread[NUM_SESSIONS];
            for (int i = 0; i < threads.length; i++) {
                // create new session
                Session session = helper.getSuperuserSession();
                TestSession ts = new TestSession("s" + i, session);
                Thread t = new Thread(ts);
                t.setName((NUM_ITERATIONS - n) + "-s" + i);
                log.println("Thread#" + i + " started");
                threads[i] = t;
                // Thread.yield();
                // Thread.sleep(100);
            for (int i = 0; i < threads.length; i++) {

            NodeIterator results = testRootNode.getNode(
            while (results.hasNext()) {
                Node node = results.nextNode();
                System.out.println("--result node- " + node.getName());

            assertEquals(1, results.getSize());

    // --------------------------------------------------------< inner classes >
    class TestSession implements Runnable {

        Session session;
        String identity;
        Random r;

        TestSession(String identity, Session s) {
            session = s;
            this.identity = identity;
            r = new Random();

        private void randomSleep() {
            long l = r.nextInt(90) + 20;
            try {
            } catch (InterruptedException ie) {

        public void run() {

            String state = "";
            try {
                this.session.getWorkspace().copy(sourcePath, destPath);
                Node newNode =
                System.out.println("--Added node- " + newNode.getName());

            } catch (Exception e) {
                log.println("Exception while " + state + ": " + e.getMessage());
            } finally {



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

View raw message