jackrabbit-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jervis Liu <jervis...@gmail.com>
Subject Re: Possible concurrency bug with Workspace.copy() ?
Date Fri, 21 Aug 2009 09:24:01 GMT
Done: https://issues.apache.org/jira/browse/JCR-2269.

Thanks,
Jervis


2009/8/21 Stefan Guggisberg <stefan.guggisberg@gmail.com>:
> hi jervis
>
> On Fri, Aug 21, 2009 at 5:41 AM, Jervis Liu<jervisliu@gmail.com> wrote:
>> Hi,
>>
>> 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.
>
> this definitely smells like a bug. do you mind posting a jira issue?
>
> thanks!
> stefan
>
>>
>> The test case is also attached for your convenience.
>>
>> Thanks,
>> 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");
>>                testNode.remove();
>>                testRootNode.save();
>>                System.out.println("---old node removed---");
>>            }
>>
>>            // create a parent node where allowSameNameSiblings is set to false
>>            Node snsfNode = testRootNode.addNode("ConcurrentCopyTestNode",
>>                    "nt:folder");
>>            testRootNode.save();
>>            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);
>>                t.start();
>>                log.println("Thread#" + i + " started");
>>                threads[i] = t;
>>                // Thread.yield();
>>                // Thread.sleep(100);
>>            }
>>            for (int i = 0; i < threads.length; i++) {
>>                threads[i].join();
>>            }
>>
>>            NodeIterator results = testRootNode.getNode(
>>                    "ConcurrentCopyTestNode").getNodes(
>>                    "CopiedFromConcurrentCopyTestNode");
>>            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 {
>>                Thread.sleep(l);
>>            } catch (InterruptedException ie) {
>>            }
>>        }
>>
>>        public void run() {
>>
>>            log.println("started.");
>>            String state = "";
>>            try {
>>                this.session.getWorkspace().copy(sourcePath, destPath);
>>                session.save();
>>                Node newNode =
>> testRootNode.getNode("ConcurrentCopyTestNode/CopiedFromConcurrentCopyTestNode");
>>                System.out.println("--Added node- " + newNode.getName());
>>
>>                session.save();
>>                randomSleep();
>>            } catch (Exception e) {
>>                log.println("Exception while " + state + ": " + e.getMessage());
>>                e.printStackTrace();
>>            } finally {
>>                session.logout();
>>            }
>>
>>            log.println("ended.");
>>        }
>>    }
>>
>> }
>>
>

Mime
View raw message