You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2010/11/30 17:04:19 UTC
svn commit: r1040601 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/
test/java/org/apache/jackrabbit/core/persistence/
Author: thomasm
Date: Tue Nov 30 16:04:18 2010
New Revision: 1040601
URL: http://svn.apache.org/viewvc?rev=1040601&view=rev
Log:
JCR-2740 On missing child node, automatically remove the entry
Added:
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java?rev=1040601&r1=1040600&r2=1040601&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java Tue Nov 30 16:04:18 2010
@@ -713,7 +713,7 @@ public class ItemManager implements Item
childIds.add(entry.getId());
}
- return new LazyItemIterator(this, childIds, parentId);
+ return new LazyItemIterator(sessionContext, childIds, parentId);
}
/**
@@ -774,7 +774,7 @@ public class ItemManager implements Item
childIds.add(id);
}
- return new LazyItemIterator(this, childIds);
+ return new LazyItemIterator(sessionContext, childIds);
}
//-------------------------------------------------< item factory methods >
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java?rev=1040601&r1=1040600&r2=1040601&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java Tue Nov 30 16:04:18 2010
@@ -31,6 +31,8 @@ import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.state.ItemStateManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,6 +55,11 @@ public class LazyItemIterator implements
/** Logger instance for this class */
private static Logger log = LoggerFactory.getLogger(LazyItemIterator.class);
+ /**
+ * The session context used to access the repository.
+ */
+ private final SessionContext sessionContext;
+
/** the item manager that is used to lazily fetch the items */
private final ItemManager itemMgr;
@@ -71,11 +78,11 @@ public class LazyItemIterator implements
/**
* Creates a new <code>LazyItemIterator</code> instance.
*
- * @param itemMgr item manager
+ * @param sessionContext session context
* @param idList list of item id's
*/
- public LazyItemIterator(ItemManager itemMgr, List< ? extends ItemId> idList) {
- this(itemMgr, idList, null);
+ public LazyItemIterator(SessionContext sessionContext, List< ? extends ItemId> idList) {
+ this(sessionContext, idList, null);
}
/**
@@ -83,12 +90,13 @@ public class LazyItemIterator implements
* a parent id as parameter. This version should be invoked to strictly return
* children nodes of a node.
*
- * @param itemMgr item manager
+ * @param sessionContext session context
* @param idList list of item id's
* @param parentId parent id.
*/
- public LazyItemIterator(ItemManager itemMgr, List< ? extends ItemId> idList, NodeId parentId) {
- this.itemMgr = itemMgr;
+ public LazyItemIterator(SessionContext sessionContext, List< ? extends ItemId> idList, NodeId parentId) {
+ this.sessionContext = sessionContext;
+ this.itemMgr = sessionContext.getSessionImpl().getItemManager();
this.idList = new ArrayList<ItemId>(idList);
this.parentId = parentId;
// prefetch first item
@@ -117,6 +125,24 @@ public class LazyItemIterator implements
log.debug("ignoring nonexistent item " + id);
// remove invalid id
idList.remove(pos);
+
+ // maybe fix the root cause
+ if (parentId != null && sessionContext.getSessionImpl().autoFixCorruptions()) {
+ try {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(id)) {
+ NodeImpl p = (NodeImpl) itemMgr.getItem(parentId);
+ p.removeChildNode((NodeId) id);
+ p.save();
+ }
+ } catch (RepositoryException e2) {
+ log.error("could not fix repository inconsistency", e);
+ // ignore
+ }
+ }
+
// try next
} catch (AccessDeniedException e) {
log.debug("ignoring nonexistent item " + id);
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=1040601&r1=1040600&r2=1040601&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Tue Nov 30 16:04:18 2010
@@ -98,6 +98,7 @@ import org.apache.jackrabbit.core.sessio
import org.apache.jackrabbit.core.state.ChildNodeEntry;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
import org.apache.jackrabbit.core.state.NodeReferences;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.PropertyState;
@@ -555,7 +556,7 @@ public class NodeImpl extends ItemImpl i
* @param id
* @param newName
* @throws RepositoryException
- * @deprecated use #renameChildNode(NodeId, Name, boolean)
+ * @deprecated use #renameChildNode(NodeId, Name, boolean)
*/
protected void renameChildNode(Name oldName, int index, NodeId id,
Name newName)
@@ -613,8 +614,24 @@ public class NodeImpl extends ItemImpl i
}
// notify target of removal
- NodeImpl childNode = itemMgr.getNode(childId, getNodeId());
- childNode.onRemove(getNodeId());
+ try {
+ NodeImpl childNode = itemMgr.getNode(childId, getNodeId());
+ childNode.onRemove(getNodeId());
+ } catch (ItemNotFoundException e) {
+ boolean ignoreError = false;
+ if (sessionContext.getSessionImpl().autoFixCorruptions()) {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(childId)) {
+ log.warn("Node " + childId + " not found, ignore", e);
+ ignoreError = true;
+ }
+ }
+ if (!ignoreError) {
+ throw e;
+ }
+ }
// remove the child node entry
if (!thisState.removeChildNodeEntry(childId)) {
@@ -663,9 +680,28 @@ public class NodeImpl extends ItemImpl i
// recursively remove child node
NodeId childId = entry.getId();
//NodeImpl childNode = (NodeImpl) itemMgr.getItem(childId);
- NodeImpl childNode = itemMgr.getNode(childId, getNodeId());
- childNode.onRemove(thisState.getNodeId());
- // remove the child node entry
+ try {
+ NodeImpl childNode = itemMgr.getNode(childId, getNodeId());
+ childNode.onRemove(thisState.getNodeId());
+ // remove the child node entry
+ } catch (ItemNotFoundException e) {
+ boolean ignoreError = false;
+ if (parentId != null && sessionContext.getSessionImpl().autoFixCorruptions()) {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(childId)) {
+ log.warn("Child named " + entry.getName() + " (index " + entry.getIndex() + ", " +
+ "node id " + childId + ") " +
+ "not found when trying to remove " + getPath() + " " +
+ "(node id " + getNodeId() + ") - ignored", e);
+ ignoreError = true;
+ }
+ }
+ if (!ignoreError) {
+ throw e;
+ }
+ }
thisState.removeChildNodeEntry(childId);
}
}
@@ -1418,7 +1454,7 @@ public class NodeImpl extends ItemImpl i
log.debug(msg);
throw new AccessDeniedException(msg);
}
-
+
ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(data.getNodeState().getChildNodeEntries());
int srcInd = -1, destInd = -1;
for (int i = 0; i < list.size(); i++) {
@@ -3022,7 +3058,7 @@ public class NodeImpl extends ItemImpl i
}
idList = filteredList;
}
- return new LazyItemIterator(itemMgr, idList);
+ return new LazyItemIterator(sessionContext, idList);
} else {
// there are no references, return empty iterator
return PropertyIteratorAdapter.EMPTY;
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=1040601&r1=1040600&r2=1040601&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Tue Nov 30 16:04:18 2010
@@ -122,6 +122,17 @@ public class SessionImpl extends Abstrac
public static final String DISABLE_CLUSTER_SYNC_ON_REFRESH =
"org.apache.jackrabbit.disableClusterSyncOnRefresh";
+ /**
+ * Name of the session attribute that controls whether repository
+ * inconsistencies should be automatically fixed when traversing over child
+ * nodes, when trying to add a child node, or removing a child node.
+ *
+ * @since Apache Jackrabbit 2.2
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-2740">JCR-2740</a>
+ */
+ public static final String AUTO_FIX_CORRUPTIONS =
+ "org.apache.jackrabbit.autoFixCorruptions";
+
private static Logger log = LoggerFactory.getLogger(SessionImpl.class);
/**
@@ -772,6 +783,20 @@ public class SessionImpl extends Abstrac
}
/**
+ * Checks whether repository inconsistencies should be automatically fixed
+ * when traversing over child nodes, when trying to add a child node, or
+ * when removing a child node.
+ *
+ * @return <code>true</code> if the {@link #AUTO_FIX_CORRUPTIONS}
+ * attribute is set, <code>false</code> otherwise
+ * @since Apache Jackrabbit 2.2
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-2740">JCR-2740</a>
+ */
+ protected boolean autoFixCorruptions() {
+ return getAttribute(AUTO_FIX_CORRUPTIONS) != null;
+ }
+
+ /**
* {@inheritDoc}
*/
public boolean hasPendingChanges() throws RepositoryException {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java?rev=1040601&r1=1040600&r2=1040601&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java Tue Nov 30 16:04:18 2010
@@ -413,7 +413,7 @@ public class VersionManagerImpl extends
Permission.VERSION_MNGMT);
List<ItemId> failedIds = new LinkedList<ItemId>();
mergeOrUpdate(state, srcWorkspaceName, failedIds, bestEffort, isShallow);
- return new LazyItemIterator(session.getItemManager(), failedIds);
+ return new LazyItemIterator(context, failedIds);
}
public String toString() {
return "versionManager.merge("
@@ -592,7 +592,7 @@ public class VersionManagerImpl extends
}
List<ItemId> failedIds = new ArrayList<ItemId>();
merge(activity, failedIds);
- return new LazyItemIterator(session.getItemManager(), failedIds);
+ return new LazyItemIterator(context, failedIds);
}
/**
@@ -642,4 +642,4 @@ public class VersionManagerImpl extends
}
}
-}
\ No newline at end of file
+}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java?rev=1040601&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java Tue Nov 30 16:04:18 2010
@@ -0,0 +1,119 @@
+/*
+ * 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.persistence;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.util.UUID;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import junit.framework.TestCase;
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.TransientRepository;
+
+/**
+ * Tests that a corrupt node is automatically fixed.
+ */
+public class AutoFixCorruptNode extends TestCase {
+
+ private final String TEST_DIR = "target/temp/" + getClass().getSimpleName();
+
+ public void setUp() throws Exception {
+ FileUtils.deleteDirectory(new File(TEST_DIR));
+ }
+
+ public void tearDown() throws Exception {
+ setUp();
+ }
+
+ public void testAutoFix() throws Exception {
+
+ // new repository
+ TransientRepository rep = new TransientRepository(new File(TEST_DIR));
+ Session s = openSession(rep, false);
+ Node root = s.getRootNode();
+
+ // add nodes /test and /test/missing
+ Node test = root.addNode("test");
+ Node missing = test.addNode("missing");
+ missing.addMixin("mix:referenceable");
+ UUID id = UUID.fromString(missing.getIdentifier());
+ s.save();
+ s.logout();
+
+ // remove the bundle for /test/missing directly in the database
+ Connection conn = DriverManager.getConnection(
+ "jdbc:derby:"+TEST_DIR+"/workspaces/default/db");
+ PreparedStatement prep = conn.prepareStatement(
+ "delete from DEFAULT_BUNDLE where NODE_ID_HI=? and NODE_ID_LO=?");
+ prep.setLong(1, id.getMostSignificantBits());
+ prep.setLong(2, id.getLeastSignificantBits());
+ prep.executeUpdate();
+ conn.close();
+
+ // login and try the operation
+ s = openSession(rep, false);
+ test = s.getRootNode().getNode("test");
+
+ // try to add a node with the same name
+ try {
+ test.addNode("missing");
+ s.save();
+ } catch (RepositoryException e) {
+ // expected
+ }
+
+ s.logout();
+
+ s = openSession(rep, true);
+ test = s.getRootNode().getNode("test");
+ // iterate over all child nodes fixes the corruption
+ NodeIterator it = test.getNodes();
+ while (it.hasNext()) {
+ it.nextNode();
+ }
+
+ // try to add a node with the same name
+ test.addNode("missing");
+ s.save();
+
+ // try to delete the parent node
+ test.remove();
+ s.save();
+
+ s.logout();
+ rep.shutdown();
+
+ FileUtils.deleteDirectory(new File("repository"));
+
+ }
+
+ private Session openSession(Repository rep, boolean autoFix) throws RepositoryException {
+ SimpleCredentials cred = new SimpleCredentials("admin", "admin".toCharArray());
+ if (autoFix) {
+ cred.setAttribute("org.apache.jackrabbit.autoFixCorruptions", "true");
+ }
+ return rep.login(cred);
+ }
+
+}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java?rev=1040601&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/TestAll.java Tue Nov 30 16:04:18 2010
@@ -0,0 +1,39 @@
+/*
+ * 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.persistence;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all test cases for this package.
+ */
+public class TestAll extends TestCase {
+
+ /**
+ * Returns a <code>Test</code> suite that executes all tests inside this
+ * package.
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite("org.apache.jackrabbit.core.persistence tests");
+
+ suite.addTestSuite(AutoFixCorruptNode.class);
+
+ return suite;
+ }
+}