You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by re...@apache.org on 2011/10/18 16:38:33 UTC

svn commit: r1185691 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: ./ version/

Author: reschke
Date: Tue Oct 18 14:38:33 2011
New Revision: 1185691

URL: http://svn.apache.org/viewvc?rev=1185691&view=rev
Log:
JCR-3115: Versioning fixup leaves persistence in a state where the node can't be made versionable again

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InconsistentVersioningState.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/InternalVersionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionManagerBase.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java?rev=1185691&r1=1185690&r2=1185691&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java Tue Oct 18 14:38:33 2011
@@ -24,6 +24,7 @@ import static org.apache.jackrabbit.spi.
 import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_VERSIONHISTORY;
 import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_VERSIONABLE;
 
+import java.util.Calendar;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -39,8 +40,11 @@ import org.apache.jackrabbit.core.state.
 import org.apache.jackrabbit.core.version.InconsistentVersioningState;
 import org.apache.jackrabbit.core.version.InternalVersion;
 import org.apache.jackrabbit.core.version.InternalVersionHistory;
-import org.apache.jackrabbit.core.version.InternalVersionManager;
+import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
 import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.util.ISO8601;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,13 +66,16 @@ class RepositoryChecker {
 
     private final ChangeLog workspaceChanges;
 
-    private final InternalVersionManager versionManager;
+    private final ChangeLog vworkspaceChanges;
+
+    private final InternalVersionManagerImpl versionManager;
 
     public RepositoryChecker(
             PersistenceManager workspace,
-            InternalVersionManager versionManager) {
+            InternalVersionManagerImpl versionManager) {
         this.workspace = workspace;
         this.workspaceChanges = new ChangeLog();
+        this.vworkspaceChanges = new ChangeLog();
         this.versionManager = versionManager;
     }
 
@@ -91,25 +98,33 @@ class RepositoryChecker {
         }
     }
 
-    public void fix() throws RepositoryException {
-        if (workspaceChanges.hasUpdates()) {
-            log.warn("Fixing repository inconsistencies");
+    private void fix(PersistenceManager pm, ChangeLog changes, String store)
+            throws RepositoryException {
+        if (changes.hasUpdates()) {
+            log.warn("Fixing " + store + " inconsistencies");
             try {
-                workspace.store(workspaceChanges);
+                pm.store(changes);
             } catch (ItemStateException e) {
-                e.printStackTrace();
-                throw new RepositoryException(
-                        "Failed to fix workspace inconsistencies", e);
+                String message = "Failed to fix " + store + " inconsistencies (aborting)";
+                log.error(message, e);
+                throw new RepositoryException(message, e);
             }
         } else {
-            log.info("No repository inconsistencies found");
+            log.info("No " + store + "  inconsistencies found");
         }
     }
 
+    public void fix() throws RepositoryException {
+        fix(workspace, workspaceChanges, "workspace");
+        fix(versionManager.getPersistenceManager(), vworkspaceChanges,
+                "versioning workspace");
+    }
+
     private void checkVersionHistory(NodeState node) {
         if (node.hasPropertyName(JCR_VERSIONHISTORY)) {
             String message = null;
             NodeId nid = node.getNodeId();
+            NodeId vhid = null;
 
             try {
                 log.debug("Checking version history of node {}", nid);
@@ -117,6 +132,8 @@ class RepositoryChecker {
                 message = "Removing references to a missing version history of node " + nid;
                 InternalVersionHistory vh = versionManager.getVersionHistoryOfNode(nid);
 
+                vhid = vh.getId();
+                
                 // additional checks, see JCR-3101
                 String intro = "Removing references to an inconsistent version history of node "
                     + nid;
@@ -144,14 +161,25 @@ class RepositoryChecker {
                     message = intro + " (root version is missing)";
                     throw new InconsistentVersioningState("root version of " + nid +" is missing.");
                 }
+            } catch (InconsistentVersioningState e) {
+                log.info(message, e);
+                NodeId nvhid = e.getVersionHistoryNodeId();
+                if (nvhid != null) {
+                    if (vhid != null && !nvhid.equals(vhid)) {
+                        log.error("vhrid returned with InconsistentVersioningState does not match the id we already had: "
+                                + vhid + " vs " + nvhid);
+                    }
+                    vhid = nvhid; 
+                }
+                removeVersionHistoryReferences(node, vhid);
             } catch (Exception e) {
                 log.info(message, e);
-                removeVersionHistoryReferences(node);
+                removeVersionHistoryReferences(node, vhid);
             }
         }
     }
 
-    private void removeVersionHistoryReferences(NodeState node) {
+    private void removeVersionHistoryReferences(NodeState node, NodeId vhid) {
         NodeState modified =
             new NodeState(node, NodeState.STATUS_EXISTING_MODIFIED, true);
 
@@ -166,6 +194,44 @@ class RepositoryChecker {
         removeProperty(modified, JCR_ISCHECKEDOUT);
 
         workspaceChanges.modified(modified);
+        
+        if (vhid != null) {
+            // attempt to rename the version history, so it doesn't interfere with
+            // a future attempt to put the node under version control again 
+            // (see JCR-3115)
+            
+            log.info("trying to rename version history of node " + node.getId());
+
+            NameFactory nf = NameFactoryImpl.getInstance();
+            
+            // Name of VHR in parent folder is ID of versionable node
+            Name vhrname = nf.create(Name.NS_DEFAULT_URI, node.getId().toString());
+
+            try {
+                NodeState vhrState = versionManager.getPersistenceManager().load(vhid);
+                NodeState vhrParentState = versionManager.getPersistenceManager().load(vhrState.getParentId());
+                
+                if (vhrParentState.hasChildNodeEntry(vhrname)) {
+                    NodeState modifiedParent = (NodeState) vworkspaceChanges.get(vhrState.getParentId());
+                    if (modifiedParent == null) {
+                        modifiedParent = new NodeState(vhrParentState, NodeState.STATUS_EXISTING_MODIFIED, true);
+                    }
+                    
+                    Calendar now = Calendar.getInstance();
+                    String appendme = " (disconnected by RepositoryChecker on "
+                            + ISO8601.format(now) + ")";
+                    modifiedParent.renameChildNodeEntry(vhid,
+                            nf.create(vhrname.getNamespaceURI(), vhrname.getLocalName() + appendme));
+
+                    vworkspaceChanges.modified(modifiedParent);
+                }
+                else {
+                    log.info("child node entry " + vhrname + " for version history not found inside parent folder.");
+                }
+            } catch (Exception ex) {
+                log.error("while trying to rename the version history", ex);
+            }
+        }
     }
 
     private void removeProperty(NodeState node, Name name) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InconsistentVersioningState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InconsistentVersioningState.java?rev=1185691&r1=1185690&r2=1185691&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InconsistentVersioningState.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InconsistentVersioningState.java Tue Oct 18 14:38:33 2011
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.version;
 
+import org.apache.jackrabbit.core.id.NodeId;
+
 /**
  * The <code>InconsistentVersionControlState</code> is used to signal
  * inconsistencies in the versioning related state of a node, such
@@ -23,6 +25,8 @@ package org.apache.jackrabbit.core.versi
  */
 public class InconsistentVersioningState extends RuntimeException {
 
+    private final NodeId versionHistoryNodeId;
+    
     /**
      * Constructs a new instance of this class with the specified detail
      * message.
@@ -32,18 +36,28 @@ public class InconsistentVersioningState
      */
     public InconsistentVersioningState(String message) {
         super(message);
+        this.versionHistoryNodeId = null;
     }
 
     /**
      * Constructs a new instance of this class with the specified detail
-     * message and root cause.
+     * message.
      *
-     * @param message   the detail message. The detail message is saved for
-     *                  later retrieval by the {@link #getMessage()} method.
-     * @param rootCause root failure cause
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     * @param rootCause root cause (or otherwise <code>null</code>)
+     * @param versionHistoryNodeId NodeId of the version history that has problems (or otherwise <code>null</code>
      */
-    public InconsistentVersioningState(String message, Throwable rootCause) {
+    public InconsistentVersioningState(String message, NodeId versionHistoryNodeId, Throwable rootCause) {
         super(message, rootCause);
+        this.versionHistoryNodeId = versionHistoryNodeId;
     }
 
+    /**
+     * @return the NodeId of the version history having problems or <code>null</code>
+     * when unknown.
+     */
+    public NodeId getVersionHistoryNodeId() {
+        return this.versionHistoryNodeId;
+    }
 }

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=1185691&r1=1185690&r2=1185691&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 Oct 18 14:38:33 2011
@@ -213,7 +213,7 @@ class InternalVersionHistoryImpl extends
             }
             return v;
         } catch (RepositoryException e) {
-            throw new IllegalArgumentException("Failed to create version " + name + ".");
+            throw new InconsistentVersioningState("Failed to create version " + name + " in VHR " + historyId + ".", historyId, null);
         }
     }
 
@@ -238,7 +238,7 @@ class InternalVersionHistoryImpl extends
                     v = new InternalVersionImpl(this, child, child.getName());
                 }
             } catch (RepositoryException e) {
-                throw new InconsistentVersioningState("Version does not have a jcr:frozenNode: " + child.getNodeId(), e);
+                throw new InconsistentVersioningState("Version does not have a jcr:frozenNode: " + child.getNodeId(), historyId, e);
             }
         }
         return v;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java?rev=1185691&r1=1185690&r2=1185691&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java Tue Oct 18 14:38:33 2011
@@ -121,7 +121,7 @@ class InternalVersionImpl extends Intern
         try {
             return (InternalFrozenNode) vMgr.getItem(getFrozenNodeId());
         } catch (RepositoryException e) {
-            throw new InconsistentVersioningState("unable to retrieve frozen node: " + e, e);
+            throw new InconsistentVersioningState("unable to retrieve frozen node: " + e, null, e);
         }
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionManagerBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionManagerBase.java?rev=1185691&r1=1185690&r2=1185691&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionManagerBase.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/version/InternalVersionManagerBase.java Tue Oct 18 14:38:33 2011
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.core.version;
 
 import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_ACTIVITY;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_ROOTVERSION;
 import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_VERSIONHISTORY;
 import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_VERSIONABLE;
 
@@ -31,6 +32,7 @@ import javax.jcr.version.VersionExceptio
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.NodeIdFactory;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.LocalItemStateManager;
 import org.apache.jackrabbit.core.state.NodeReferences;
@@ -319,12 +321,14 @@ abstract class InternalVersionManagerBas
             if (parent != null && parent.hasNode(name)) {
                 NodeStateEx history = parent.getNode(name, 1);
                 if (history == null) {
-                    throw new InconsistentVersioningState("Unexpected failure to get child node " + name + " on parent node" + parent.getNodeId());
+                    throw new InconsistentVersioningState("Unexpected failure to get child node " + name + " on parent node " + parent.getNodeId());
+                }
+                ChildNodeEntry rootv = history.getState().getChildNodeEntry(JCR_ROOTVERSION, 1);
+                if (rootv == null) {
+                    throw new InconsistentVersioningState("missing child node entry for " + JCR_ROOTVERSION + " on version history node " + history.getNodeId());
                 }
-                Name root = NameConstants.JCR_ROOTVERSION;
-                info = new VersionHistoryInfo(
-                        history.getNodeId(),
-                        history.getState().getChildNodeEntry(root, 1).getId());
+                info = new VersionHistoryInfo(history.getNodeId(),
+                        rootv.getId());
             }
         } finally {
             lock.release();