You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/05/26 12:26:14 UTC

svn commit: r778645 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/version/ test/java/org/apache/jackrabbit/core/version/

Author: jukka
Date: Tue May 26 10:26:13 2009
New Revision: 778645

URL: http://svn.apache.org/viewvc?rev=778645&view=rev
Log:
JCR-134: Unreferenced VersionHistory should be deleted automatically

Applied patch contributed by Sébastien Launay

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java?rev=778645&r1=778644&r2=778645&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/AbstractVersionManager.java Tue May 26 10:26:13 2009
@@ -40,8 +40,8 @@
 /**
  * Base implementation of the {@link VersionManager} interface.
  * <p/>
- * All read operations must aquire the read lock before reading, all write
- * operations must aquire the write lock.
+ * All read operations must acquire the read lock before reading, all write
+ * operations must acquire the write lock.
  */
 abstract class AbstractVersionManager implements VersionManager {
 
@@ -291,7 +291,7 @@
     /**
      * Returns the item with the given persistent id. Subclass responsibility.
      * <p/>
-     * Please note, that the overridden method must aquire the readlock before
+     * Please note, that the overridden method must acquire the readlock before
      * reading the state manager.
      *
      * @param id the id of the item
@@ -312,18 +312,31 @@
 
     /**
      * Checks if there are item references (from outside the version storage)
-     * that reference the given version item. Subclass responsiblity.
+     * that reference the given node. Subclass responsibility.
      * <p/>
-     * Please note, that the overridden method must aquire the readlock before
+     * Please note, that the overridden method must acquire the readlock before
      * reading the state manager.
      *
-     * @param item version item
+     * @param id the id of the node
      * @return <code>true</code> if there are item references from outside the
      *         version storage; <code>false</code> otherwise.
      * @throws RepositoryException if an error occurs while reading from the
      *                             repository.
      */
-    protected abstract boolean hasItemReferences(InternalVersionItem item)
+    protected abstract boolean hasItemReferences(NodeId id)
+            throws RepositoryException;
+
+    /**
+     * Returns the node with the given persistent id. Subclass responsibility.
+     * <p/>
+     * Please note, that the overridden method must acquire the readlock before
+     * reading the state manager.
+     *
+     * @param id the id of the node
+     * @throws RepositoryException if an error occurs while reading from the
+     *                             repository.
+     */
+    protected abstract NodeStateEx getNodeStateEx(NodeId id)
             throws RepositoryException;
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java?rev=778645&r1=778644&r2=778645&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java Tue May 26 10:26:13 2009
@@ -375,7 +375,7 @@
             throw new VersionException(msg);
         }
         // check if any references (from outside the version storage) exist on this version
-        if (vMgr.hasItemReferences(v)) {
+        if (vMgr.hasItemReferences(v.getId())) {
             throw new ReferentialIntegrityException("Unable to remove version. At least once referenced.");
         }
 
@@ -396,8 +396,25 @@
         nameCache.remove(versionName);
         vMgr.versionDestroyed(v);
 
-        // store changes
-        node.store();
+        // Check if this was the last version in addition to the root version
+        if (!vMgr.hasItemReferences(node.getNodeId())) {
+            log.debug("Current version history has no references");
+            NodeStateEx[] childNodes = node.getChildNodes();
+
+            // Check if there is only root version and version labels nodes
+            if (childNodes.length == 2) {
+                log.debug("Removing orphan version history as it contains only two children");
+                NodeStateEx parentNode = vMgr.getNodeStateEx(node.getParentId());
+                // Remove version history node
+                parentNode.removeNode(node.getName());
+                // store changes for this node and his children
+                parentNode.store();
+            }
+        } else {
+            log.debug("Current version history has at least one reference");
+            // store changes
+            node.store();
+        }
 
         // now also remove from labelCache
         for (int i = 0; i < labels.length; i++) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java?rev=778645&r1=778644&r2=778645&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java Tue May 26 10:26:13 2009
@@ -411,14 +411,19 @@
     /**
      * {@inheritDoc}
      */
-    protected boolean hasItemReferences(InternalVersionItem item)
+    protected boolean hasItemReferences(NodeId id)
+            throws RepositoryException {
+        return stateMgr.hasNodeReferences(new NodeReferencesId(id));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected NodeStateEx getNodeStateEx(NodeId parentNodeId)
             throws RepositoryException {
         try {
-            NodeReferences refs = stateMgr.getNodeReferences(
-                    new NodeReferencesId(item.getId()));
-            return refs.hasReferences();
-        } catch (NoSuchItemStateException e) {
-            return false;
+            NodeState state = (NodeState) stateMgr.getItemState(parentNodeId);
+            return new NodeStateEx(stateMgr, ntReg, state, null);
         } catch (ItemStateException e) {
             throw new RepositoryException(e);
         }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java?rev=778645&r1=778644&r2=778645&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java Tue May 26 10:26:13 2009
@@ -370,9 +370,22 @@
     /**
      * {@inheritDoc}
      */
-    protected boolean hasItemReferences(InternalVersionItem item)
+    protected boolean hasItemReferences(NodeId id)
             throws RepositoryException {
-        return session.getNodeById(item.getId()).getReferences().hasNext();
+        return session.getNodeById(id).getReferences().hasNext();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected NodeStateEx getNodeStateEx(NodeId parentNodeId)
+            throws RepositoryException {
+        try {
+            NodeState state = (NodeState) stateMgr.getItemState(parentNodeId);
+            return new NodeStateEx(stateMgr, ntReg, state, null);
+        } catch (ItemStateException e) {
+            throw new RepositoryException(e);
+        }
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java?rev=778645&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/version/RemoveOrphanVersionHistoryTest.java Tue May 26 10:26:13 2009
@@ -0,0 +1,154 @@
+/*
+ * 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.version;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Workspace;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+/**
+ * Test case for JCR-134.
+ */
+public class RemoveOrphanVersionHistoryTest extends AbstractJCRTest {
+
+    /**
+     * Test orphan version history cleaning in a single workspace.
+     * @throws RepositoryException if an error occurs.
+     */
+    public void testRemoveOrphanVersionHistory() throws RepositoryException {
+        Node n = testRootNode.addNode(nodeName1);
+        n.addMixin(mixVersionable);
+        testRootNode.save();
+        Session session = n.getSession();
+        VersionHistory vh = n.getVersionHistory();
+        String vhUuid = vh.getUUID();
+        assertExists(session, vhUuid);
+
+        // First version
+        Version v10 = n.checkin();
+        n.checkout();
+
+        // Second version
+        Version v11 = n.checkin();
+        n.checkout();
+
+        // Remove node
+        n.remove();
+        testRootNode.save();
+        assertExists(session, vhUuid);
+
+        // Remove the first version
+        vh.removeVersion(v10.getName());
+        assertExists(session, vhUuid);
+
+        // Remove the second and last version
+        vh.removeVersion(v11.getName());
+
+        try {
+            session.getNodeByUUID(vhUuid);
+            fail("Orphan version history must have been removed");
+        } catch (ItemNotFoundException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * Test orphan version history cleaning in multiple workspace.
+     * @throws RepositoryException if an error occurs.
+     */
+    public void testWorkspaceRemoveOrphanVersionHistory() throws RepositoryException {
+        Node n = testRootNode.addNode(nodeName1);
+        n.addMixin(mixVersionable);
+        testRootNode.save();
+        Session session = n.getSession();
+        VersionHistory vh = n.getVersionHistory();
+        String vhUuid = vh.getUUID();
+        assertExists(session, vhUuid);
+
+        // First version
+        Version v10 = n.checkin();
+        n.checkout();
+
+        Workspace defaultWorkspace = n.getSession().getWorkspace();
+        Session otherWsSession = n.getSession().getRepository().login(new SimpleCredentials("superuser", "".toCharArray()), workspaceName);
+        // Clone the node in another workspace
+        otherWsSession.getWorkspace().clone(defaultWorkspace.getName(), n.getPath(), n.getPath(), false);
+        Node otherWsRootNode = otherWsSession.getRootNode();
+        Node clonedNode = otherWsRootNode.getNode(n.getPath().substring(1));
+        // Ensure that version histories are the same
+        assertEquals(vhUuid, clonedNode.getVersionHistory().getUUID());
+
+        Version v11 = clonedNode.checkin();
+        clonedNode.checkout();
+
+        // Remove node
+        n.remove();
+        testRootNode.save();
+        assertExists(session, vhUuid);
+        assertExists(otherWsSession, vhUuid);
+
+        // Remove the first version
+        vh.removeVersion(v10.getName());
+        assertExists(session, vhUuid);
+        assertExists(otherWsSession, vhUuid);
+
+        // Remove cloned node
+        clonedNode.remove();
+        otherWsRootNode.save();
+        assertExists(session, vhUuid);
+        assertExists(otherWsSession, vhUuid);
+
+        // Remove the last version
+        vh.removeVersion(v11.getName());
+
+        try {
+            session.getNodeByUUID(vhUuid);
+            fail("Orphan version history must have been removed from the default workspace");
+        } catch (ItemNotFoundException e) {
+            // Expected
+        }
+
+        try {
+            otherWsSession.getNodeByUUID(vhUuid);
+            fail("Orphan version history must have been removed from the other workspace");
+        } catch (ItemNotFoundException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * Assert that a node exists in a session.
+     * @param session the session.
+     * @param uuid the node's UUID.
+     * @throws RepositoryException if an error occurs.
+     */
+    protected void assertExists(Session session, String uuid) throws RepositoryException
+    {
+        try {
+            session.getNodeByUUID(uuid);
+        } catch (ItemNotFoundException e) {
+            fail("Unknown uuid: " + uuid);
+        }
+    }
+}

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