Return-Path: Delivered-To: apmail-jackrabbit-dev-archive@www.apache.org Received: (qmail 48462 invoked from network); 21 Aug 2009 09:19:18 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 21 Aug 2009 09:19:18 -0000 Received: (qmail 76181 invoked by uid 500); 21 Aug 2009 09:19:39 -0000 Delivered-To: apmail-jackrabbit-dev-archive@jackrabbit.apache.org Received: (qmail 76110 invoked by uid 500); 21 Aug 2009 09:19:39 -0000 Mailing-List: contact dev-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list dev@jackrabbit.apache.org Received: (qmail 76097 invoked by uid 99); 21 Aug 2009 09:19:39 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 21 Aug 2009 09:19:39 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.140] (HELO brutus.apache.org) (140.211.11.140) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 21 Aug 2009 09:19:35 +0000 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id D5487234C1EA for ; Fri, 21 Aug 2009 02:19:14 -0700 (PDT) Message-ID: <646814016.1250846354872.JavaMail.jira@brutus> Date: Fri, 21 Aug 2009 02:19:14 -0700 (PDT) From: "Jervis Liu (JIRA)" To: dev@jackrabbit.apache.org Subject: [jira] Created: (JCR-2269) Possible concurrency bug with Workspace.copy() MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 X-Virus-Checked: Checked by ClamAV on apache.org 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 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. 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."); } } } -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.