Return-Path: Delivered-To: apmail-jackrabbit-users-archive@minotaur.apache.org Received: (qmail 51119 invoked from network); 21 Aug 2009 09:24:11 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 21 Aug 2009 09:24:11 -0000 Received: (qmail 84079 invoked by uid 500); 21 Aug 2009 09:24:33 -0000 Delivered-To: apmail-jackrabbit-users-archive@jackrabbit.apache.org Received: (qmail 84035 invoked by uid 500); 21 Aug 2009 09:24:33 -0000 Mailing-List: contact users-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: users@jackrabbit.apache.org Delivered-To: mailing list users@jackrabbit.apache.org Received: (qmail 84021 invoked by uid 99); 21 Aug 2009 09:24:33 -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:24:33 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of jervisliu@gmail.com designates 209.85.216.188 as permitted sender) Received: from [209.85.216.188] (HELO mail-px0-f188.google.com) (209.85.216.188) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 21 Aug 2009 09:24:23 +0000 Received: by pxi26 with SMTP id 26so4000413pxi.13 for ; Fri, 21 Aug 2009 02:24:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=oPRcrsGxOzddpN33qmlRlbvtZXjnB83E6HtpkkFVXqw=; b=Ej2kOKcfPok05cpj/IlKm+Dx+YQdF3cyocrgJGVf3zdrAp9ot5TXoi3om2Th2z0BHh 08P0AILeJNU8TwStuSYKFpBl+VzeXwQ8LRIN0Jf0wMbUAo+i0WOA3Nk73dLwyCeNpNYk o6wA8DPzwCzA0DQa2lfHoXpCcJpDnIhuvVwR4= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=AUD5COAVvEwayf9sS4jN98uauJ3EAse/qidca1cyCIYPQs4hA2JlQ+/fO+dUMFMG8p RWgP2ZOZDj7NgWLk3Y9vNJgVa6gGyLuqB0TRg4wsHDr8qZQ3KpMLlFSFt7vSO6Zn0mcp u6mXUXxVQnBOlBUWOgxCEJYZEQvYqNLgi04gs= MIME-Version: 1.0 Received: by 10.142.210.13 with SMTP id i13mr53250wfg.147.1250846641948; Fri, 21 Aug 2009 02:24:01 -0700 (PDT) In-Reply-To: <90a8d1c00908210057v4fbd34d7u2eb9997fc4aa833d@mail.gmail.com> References: <797beb000908202041r488b714t3b3187728e04d9d9@mail.gmail.com> <90a8d1c00908210057v4fbd34d7u2eb9997fc4aa833d@mail.gmail.com> Date: Fri, 21 Aug 2009 17:24:01 +0800 Message-ID: <797beb000908210224g7ff6a6d0h82e61b4dfbac490@mail.gmail.com> Subject: Re: Possible concurrency bug with Workspace.copy() ? From: Jervis Liu To: users@jackrabbit.apache.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org Done: https://issues.apache.org/jira/browse/JCR-2269. Thanks, Jervis 2009/8/21 Stefan Guggisberg : > hi jervis > > On Fri, Aug 21, 2009 at 5:41 AM, Jervis Liu 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.". =A0"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. =A0The 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). =A0Can 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 { >> >> =A0 =A0private static final int NUM_ITERATIONS =3D 40; >> =A0 =A0private static final int NUM_SESSIONS =3D 2; >> >> =A0 =A0String sourcePath; >> =A0 =A0String destPath; >> >> =A0 =A0public void testConcurrentCopy() throws Exception { >> =A0 =A0 =A0 =A0for (int n =3D 0; n < NUM_ITERATIONS; n++) { >> =A0 =A0 =A0 =A0 =A0 =A0System.out.println("---Iteration---- " + n); >> >> =A0 =A0 =A0 =A0 =A0 =A0// clean up testRoot first >> =A0 =A0 =A0 =A0 =A0 =A0if (testRootNode.hasNode("ConcurrentCopyTestNode"= )) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Node testNode =3D testRootNode.getNode("C= oncurrentCopyTestNode"); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0testNode.remove(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0testRootNode.save(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0System.out.println("---old node removed--= -"); >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0// create a parent node where allowSameNameSiblin= gs is set to false >> =A0 =A0 =A0 =A0 =A0 =A0Node snsfNode =3D testRootNode.addNode("Concurren= tCopyTestNode", >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"nt:folder"); >> =A0 =A0 =A0 =A0 =A0 =A0testRootNode.save(); >> =A0 =A0 =A0 =A0 =A0 =A0sourcePath =3D snsfNode.getPath(); >> =A0 =A0 =A0 =A0 =A0 =A0destPath =3D sourcePath + "/" + "CopiedFromConcur= rentCopyTestNode"; >> =A0 =A0 =A0 =A0 =A0 =A0System.out.println("---sourcePath----------------= -" + sourcePath); >> =A0 =A0 =A0 =A0 =A0 =A0System.out.println("---destPath-----------------"= + destPath); >> >> =A0 =A0 =A0 =A0 =A0 =A0// firstly we verify it works with single thread. >> =A0 =A0 =A0 =A0 =A0 =A0Session rootSession =3D helper.getSuperuserSessio= n(); >> =A0 =A0 =A0 =A0 =A0 =A0rootSession.getWorkspace().copy(sourcePath, destP= ath + "test"); >> >> =A0 =A0 =A0 =A0 =A0 =A0// copy again to same destPath, expect an ItemExi= stsException >> =A0 =A0 =A0 =A0 =A0 =A0try { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rootSession.getWorkspace().copy(sourcePat= h, destPath + "test"); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fail("Node exists below '" + destPath + "= '. Test should fail."); >> =A0 =A0 =A0 =A0 =A0 =A0} catch (ItemExistsException e) { >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0Thread[] threads =3D new Thread[NUM_SESSIONS]; >> =A0 =A0 =A0 =A0 =A0 =A0for (int i =3D 0; i < threads.length; i++) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// create new session >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Session session =3D helper.getSuperuserSe= ssion(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0TestSession ts =3D new TestSession("s" + = i, session); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Thread t =3D new Thread(ts); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0t.setName((NUM_ITERATIONS - n) + "-s" + i= ); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0t.start(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0log.println("Thread#" + i + " started"); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0threads[i] =3D t; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Thread.yield(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Thread.sleep(100); >> =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0for (int i =3D 0; i < threads.length; i++) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0threads[i].join(); >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0NodeIterator results =3D testRootNode.getNode( >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"ConcurrentCopyTestNode").getNode= s( >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"CopiedFromConcurrentCopyTestNode= "); >> =A0 =A0 =A0 =A0 =A0 =A0while (results.hasNext()) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Node node =3D results.nextNode(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0System.out.println("--result node- " + no= de.getName()); >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0assertEquals(1, results.getSize()); >> =A0 =A0 =A0 =A0} >> =A0 =A0} >> >> =A0 =A0// --------------------------------------------------------< inne= r classes > >> =A0 =A0class TestSession implements Runnable { >> >> =A0 =A0 =A0 =A0Session session; >> =A0 =A0 =A0 =A0String identity; >> =A0 =A0 =A0 =A0Random r; >> >> =A0 =A0 =A0 =A0TestSession(String identity, Session s) { >> =A0 =A0 =A0 =A0 =A0 =A0session =3D s; >> =A0 =A0 =A0 =A0 =A0 =A0this.identity =3D identity; >> =A0 =A0 =A0 =A0 =A0 =A0r =3D new Random(); >> =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0private void randomSleep() { >> =A0 =A0 =A0 =A0 =A0 =A0long l =3D r.nextInt(90) + 20; >> =A0 =A0 =A0 =A0 =A0 =A0try { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Thread.sleep(l); >> =A0 =A0 =A0 =A0 =A0 =A0} catch (InterruptedException ie) { >> =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0public void run() { >> >> =A0 =A0 =A0 =A0 =A0 =A0log.println("started."); >> =A0 =A0 =A0 =A0 =A0 =A0String state =3D ""; >> =A0 =A0 =A0 =A0 =A0 =A0try { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.session.getWorkspace().copy(sourcePa= th, destPath); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0session.save(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Node newNode =3D >> testRootNode.getNode("ConcurrentCopyTestNode/CopiedFromConcurrentCopyTes= tNode"); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0System.out.println("--Added node- " + new= Node.getName()); >> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0session.save(); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0randomSleep(); >> =A0 =A0 =A0 =A0 =A0 =A0} catch (Exception e) { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0log.println("Exception while " + state + = ": " + e.getMessage()); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0e.printStackTrace(); >> =A0 =A0 =A0 =A0 =A0 =A0} finally { >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0session.logout(); >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> =A0 =A0 =A0 =A0 =A0 =A0log.println("ended."); >> =A0 =A0 =A0 =A0} >> =A0 =A0} >> >> } >> >