jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sch...@apache.org
Subject svn commit: r1327180 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ test/java/org/apache/jackrabbit/core/ test/java/org/apache/jackrabbit/core/integration/daily/
Date Tue, 17 Apr 2012 16:52:08 GMT
Author: schans
Date: Tue Apr 17 16:52:08 2012
New Revision: 1327180

URL: http://svn.apache.org/viewvc?rev=1327180&view=rev
Log:
JCR-3292: Prevent workspace.move() from causing data inconsistencies

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=1327180&r1=1327179&r2=1327180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
Tue Apr 17 16:52:08 2012
@@ -547,7 +547,9 @@ public class BatchedItemOperations exten
             srcNameIndex = 1;
         }
 
+        stateMgr.store(target);
         if (renameOnly) {
+            stateMgr.store(srcParent);
             // change child node entry
             destParent.renameChildNodeEntry(srcPath.getName(), srcNameIndex,
                     destPath.getName());
@@ -561,6 +563,9 @@ public class BatchedItemOperations exten
                 throw new UnsupportedRepositoryOperationException(msg);
             }
 
+            stateMgr.store(srcParent);
+            stateMgr.store(destParent);
+
             // do move:
             // 1. remove child node entry from old parent
             if (srcParent.removeChildNodeEntry(target.getNodeId())) {
@@ -571,14 +576,6 @@ public class BatchedItemOperations exten
             }
         }
 
-        // store states
-        stateMgr.store(target);
-        if (renameOnly) {
-            stateMgr.store(srcParent);
-        } else {
-            stateMgr.store(destParent);
-            stateMgr.store(srcParent);
-        }
         return target.getNodeId();
     }
 

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java?rev=1327180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
Tue Apr 17 16:52:08 2012
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core;
+
+import java.util.Random;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.integration.random.operation.Operation;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
+
+/**
+ * <code>ConcurrentAddMoveRemoveTest</code> performs a test with 5 threads which
+ * concurrently add, (workspace) move and remove nodes. This test is intended to 
+ * make sure these concurrent actions don't lead to inconsistencies in the database.
+ * See also: JCR-3292.
+ */
+public class ConcurrentAddMoveRemoveTest extends AbstractConcurrencyTest {
+
+    private static final int RUN_NUM_SECONDS = 20;
+
+    private long end;
+
+    private String folder1Path;
+    private String folder2Path;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        end = System.currentTimeMillis() + RUN_NUM_SECONDS * 1000;
+        folder1Path = testRootNode.addNode("folder1").getPath();
+        folder2Path = testRootNode.addNode("folder2").getPath();
+        testRootNode.getSession().save();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        ConsistencyReport consistencyReport = TestHelper.checkConsistency(testRootNode.getSession(),
false, null);
+        //for (ReportItem item : consistencyReport.getItems()) {
+        //    System.out.println(item.getMessage());
+        //}
+        assertTrue(consistencyReport.getItems().size() == 0);
+        super.tearDown();
+    }
+
+    public void testRandomOperations() throws RepositoryException {
+        runTask(new AddMoveRemoveTask(end, folder1Path, folder2Path), 5, testRootNode.getPath());
+    }
+
+    public static class AddMoveRemoveTask implements Task {
+
+        private final long end;
+        private final String folder1Path;
+        private final String folder2Path;
+
+        private final Random random = new Random();
+
+        public AddMoveRemoveTask(long end, String folder1Path, String folder2Path) {
+            this.end = end;
+            this.folder1Path = folder1Path;
+            this.folder2Path = folder2Path;
+        }
+
+        public void execute(final Session session, final Node test) throws RepositoryException
{
+            while (end > System.currentTimeMillis()) {
+                try {
+                    getRandomOperation(session).execute();
+                } catch (RepositoryException e) {
+                    // RepositoryExceptions are expected during concurrent actions.
+                    session.refresh(false);
+                } catch (Exception e) {
+                    // only a RepositoryException is allowed from a Task
+                    throw new RepositoryException("Failure during concurrent execution",
e);
+                }
+            }
+        }
+
+        private Operation getRandomOperation(Session session) throws RepositoryException
{
+            switch (random.nextInt(3)) {
+            case 0:
+                return new Add(session, getRandomParent());
+            case 1: {
+                String folderPath = getRandomParent();
+                return new WorkspaceMove(session, getRandomChild(session, folderPath),
+                        folderPath.equals(folder1Path) ? folder2Path : folder1Path);
+            }
+            default: {
+                String folderPath = getRandomParent();
+                return new Remove(session, getRandomChild(session, folderPath));
+            }
+            }
+        }
+
+        private String getRandomChild(Session session, String parentPath) throws RepositoryException
{
+            Node parent = session.getNode(parentPath);
+            NodeIterator nodes = parent.getNodes();
+            int size = (int) nodes.getSize();
+            if (size > 0) {
+                int i = 1;
+                int offset = random.nextInt(size);
+                while (nodes.hasNext()) {
+                    if (i == offset) {
+                        return nodes.nextNode().getPath();
+                    }
+                    nodes.nextNode();
+                    i++;
+                }
+            }
+            return null;
+        }
+
+        private String getRandomParent() {
+            switch (random.nextInt(2)) {
+            case 0:
+                return folder1Path;
+            default:
+                return folder2Path;
+            }
+        }
+
+        private class Add extends Operation {
+
+            private final String name;
+
+            public Add(Session s, String folderPath) {
+                super(s, folderPath);
+                this.name = getRandomText(4);
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                getNode().addNode(name);
+                getSession().save();
+                return null;
+            }
+        }
+
+        private class Remove extends Operation {
+
+            public Remove(Session s, String path) {
+                super(s, path);
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                if (getPath() != null) {
+                    getNode().remove();
+                    getSession().save();
+                }
+                return null;
+            }
+
+        }
+
+        private class WorkspaceMove extends Operation {
+
+            private final String folderPath;
+
+            public WorkspaceMove(Session s, String path, String folderPath) {
+                super(s, path);
+                this.folderPath = folderPath;
+            }
+
+            @Override
+            public NodeIterator execute() throws Exception {
+                if (getPath() != null) {
+                    String destination = folderPath + "/" + getRandomText(4);
+                    getSession().getWorkspace().move(getPath(), destination);
+                }
+                return null;
+            }
+
+        }
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentAddMoveRemoveTest.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java?rev=1327180&r1=1327179&r2=1327180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/integration/daily/DailyIntegrationTest.java
Tue Apr 17 16:52:08 2012
@@ -20,6 +20,7 @@ import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 import org.apache.jackrabbit.core.ConcurrencyTest;
+import org.apache.jackrabbit.core.ConcurrentAddMoveRemoveTest;
 import org.apache.jackrabbit.core.ConcurrentCheckinMixedTransactionTest;
 import org.apache.jackrabbit.core.ConcurrentLoginTest;
 import org.apache.jackrabbit.core.ConcurrentNodeModificationTest;
@@ -54,6 +55,7 @@ public class DailyIntegrationTest extend
         suite.addTestSuite(ConcurrentVersioningTest.class);
         suite.addTestSuite(ConcurrentVersioningWithTransactionsTest.class);
         suite.addTestSuite(ConcurrentCheckinMixedTransactionTest.class);
+        suite.addTestSuite(ConcurrentAddMoveRemoveTest.class);
         suite.addTestSuite(LockTest.class);
         suite.addTestSuite(ReadVersionsWhileModified.class);
         suite.addTestSuite(ConcurrentLockingTest.class);



Mime
View raw message