Author: unico
Date: Sun Feb 10 08:15:20 2013
New Revision: 1444501
URL: http://svn.apache.org/r1444501
Log:
JCR-3516 also report and fix wrong parent relation in the index
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/SearchIndexConsistencyCheckTest.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java?rev=1444501&r1=1444500&r2=1444501&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ConsistencyCheck.java
Sun Feb 10 08:15:20 2013
@@ -19,7 +19,7 @@ package org.apache.jackrabbit.core.query
import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.persistence.IterablePersistenceManager;
import org.apache.jackrabbit.core.persistence.PersistenceManager;
-import org.apache.jackrabbit.core.persistence.check.ConsistencyChecker;
+import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateManager;
import org.apache.jackrabbit.core.state.NoSuchItemStateException;
import org.apache.jackrabbit.core.state.NodeState;
@@ -284,23 +284,34 @@ public class ConsistencyCheck {
}
Document d = reader.document(i, FieldSelectors.UUID_AND_PARENT);
NodeId id = new NodeId(d.get(FieldNames.UUID));
- String parentUUIDString = d.get(FieldNames.PARENT);
- NodeId parentId = null;
- if (parentUUIDString.length() > 0) {
- parentId = new NodeId(parentUUIDString);
+ String parent = d.get(FieldNames.PARENT);
+ NodeId parentId;
+ if (parent != null && !parent.isEmpty()) {
+ parentId = new NodeId(parent);
+ } else {
+ continue;
}
- boolean parentExists = parentId != null && nodeIds.containsKey(parentId);
+ boolean parentExists = nodeIds.containsKey(parentId);
boolean parentIndexed = parentExists && nodeIds.get(parentId);
- if (parentId == null || parentIndexed) {
+ if (parentIndexed) {
continue;
}
- // parent is missing
+ // parent is missing from index
if (parentExists) {
errors.add(new MissingAncestor(id, parentId));
} else {
- errors.add(new UnknownParent(id, parentId));
+ try {
+ final ItemState itemState = stateMgr.getItemState(id);
+ if (parentId.equals(itemState.getParentId())) {
+ // orphaned node
+ errors.add(new UnknownParent(id, parentId));
+ } else {
+ errors.add(new WrongParent(id, parentId, itemState.getParentId()));
+ }
+ } catch (ItemStateException ignored) {
+ }
}
}
} finally {
@@ -439,7 +450,7 @@ public class ConsistencyCheck {
while (ancestorId != null && nodeIds.containsKey(ancestorId) &&
nodeIds.get(ancestorId)) {
try {
NodeState n = (NodeState) stateMgr.getItemState(ancestorId);
- log.info("Reparing missing node " + getPath(n) + " (" + ancestorId +
")");
+ log.info("Repairing missing node " + getPath(n) + " (" + ancestorId +
")");
Document d = index.createDocument(n);
index.addDocument(d);
nodeIds.put(n.getNodeId(), Boolean.TRUE);
@@ -454,7 +465,7 @@ public class ConsistencyCheck {
}
/**
- * The parent of a node is not available through the ItemStateManager.
+ * The parent of a node is not in the repository
*/
private static class UnknownParent extends ConsistencyCheckError {
@@ -479,6 +490,43 @@ public class ConsistencyCheck {
}
/**
+ * The parent as indexed does not correspond with the actual parent in the repository
+ */
+ private class WrongParent extends ConsistencyCheckError {
+
+ private WrongParent(NodeId id, NodeId indexedParentId, NodeId actualParentId) {
+ super("Node " + id + " has wrong parent: " + indexedParentId + ", should be :
" + actualParentId, id);
+ }
+
+ @Override
+ public boolean repairable() {
+ return true;
+ }
+
+ /**
+ * Reindex node.
+ */
+ @Override
+ void repair() throws IOException {
+ index.removeAllDocuments(id);
+ try {
+ NodeState node = (NodeState) stateMgr.getItemState(id);
+ log.info("Re-indexing node with wrong parent in index: " + getPath(node));
+ Document d = index.createDocument(node);
+ index.addDocument(d);
+ nodeIds.put(node.getNodeId(), Boolean.TRUE);
+ } catch (NoSuchItemStateException e) {
+ log.info("Not re-indexing node with wrong parent because node no longer exists");
+ } catch (ItemStateException e) {
+ throw new IOException(e.toString());
+ } catch (RepositoryException e) {
+ throw new IOException(e.toString());
+ }
+ }
+
+ }
+
+ /**
* A node is present multiple times in the index.
*/
private class MultipleEntries extends ConsistencyCheckError {
@@ -510,6 +558,8 @@ public class ConsistencyCheck {
Document d = index.createDocument(node);
index.addDocument(d);
nodeIds.put(node.getNodeId(), Boolean.TRUE);
+ } catch (NoSuchItemStateException e) {
+ log.info("Not re-indexing node with multiple occurrences because node no
longer exists");
} catch (ItemStateException e) {
throw new IOException(e.toString());
} catch (RepositoryException e) {
@@ -560,11 +610,14 @@ public class ConsistencyCheck {
void repair() throws IOException {
try {
NodeState nodeState = (NodeState) stateMgr.getItemState(id);
+ log.info("Adding missing node to index: " + getPath(nodeState));
final Iterator<NodeId> remove = Collections.<NodeId>emptyList().iterator();
final Iterator<NodeState> add = Collections.singletonList(nodeState).iterator();
handler.updateNodes(remove, add);
} catch (RepositoryException e) {
throw new IOException(e.toString());
+ } catch (NoSuchItemStateException e) {
+ log.info("Not adding missing node because node no longer exists");
} catch (ItemStateException e) {
throw new IOException(e.toString());
}
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/SearchIndexConsistencyCheckTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/SearchIndexConsistencyCheckTest.java?rev=1444501&r1=1444500&r2=1444501&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/SearchIndexConsistencyCheckTest.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/SearchIndexConsistencyCheckTest.java
Sun Feb 10 08:15:20 2013
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.core.query
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -101,6 +102,71 @@ public class SearchIndexConsistencyCheck
assertTrue("Consistency check still reports errors", searchIndex.runConsistencyCheck().getErrors().isEmpty());
}
+ public void testIndexMissesAncestor() throws Exception {
+ Session s = getHelper().getSuperuserSession();
+ SearchManager searchManager = TestHelper.getSearchManager(s);
+ SearchIndex searchIndex = (SearchIndex) searchManager.getQueryHandler();
+
+ Node foo = testRootNode.addNode("foo");
+ Node bar = foo.addNode("bar");
+ testRootNode.getSession().save();
+ NodeId fooId = new NodeId(foo.getIdentifier());
+ NodeId barId = new NodeId(bar.getIdentifier());
+
+ Iterator<NodeId> remove = Collections.singletonList(fooId).iterator();
+ Iterator<NodeState> add = Collections.<NodeState>emptyList().iterator();
+
+ searchIndex.updateNodes(remove, add);
+
+ ConsistencyCheck consistencyCheck = searchIndex.runConsistencyCheck();
+ List<ConsistencyCheckError> errors = consistencyCheck.getErrors();
+
+ assertEquals("Expected 2 index consistency errors", 2, errors.size());
+
+ assertEquals("Different node was reported to have missing parent", errors.get(0).id,
barId);
+ assertEquals("Different node was reported to be missing", errors.get(1).id, fooId);
+
+ consistencyCheck.repair(false);
+
+ assertTrue("Index was not repaired properly", searchIndexContainsNode(searchIndex,
fooId));
+
+ assertTrue("Consistency check still reports errors", searchIndex.runConsistencyCheck().getErrors().isEmpty());
+ }
+
+ public void testIndexContainsMultipleEntries() throws Exception {
+ Session s = getHelper().getSuperuserSession();
+ SearchManager searchManager = TestHelper.getSearchManager(s);
+ SearchIndex searchIndex = (SearchIndex) searchManager.getQueryHandler();
+
+ Node foo = testRootNode.addNode("foo");
+ testRootNode.getSession().save();
+ NodeId fooId = new NodeId(foo.getIdentifier());
+
+ NodeState nodeState = new NodeState(fooId, null, null, 1, false);
+ Iterator<NodeId> remove = Collections.<NodeId>emptyList().iterator();
+ Iterator<NodeState> add = Arrays.asList(nodeState).iterator();
+
+ searchIndex.updateNodes(remove, add);
+
+ searchIndex.flush();
+
+ remove = Collections.<NodeId>emptyList().iterator();
+ add = Arrays.asList(nodeState).iterator();
+
+ searchIndex.updateNodes(remove, add);
+
+ ConsistencyCheck consistencyCheck = searchIndex.runConsistencyCheck();
+ List<ConsistencyCheckError> errors = consistencyCheck.getErrors();
+
+ assertEquals("Expected 1 index consistency error", 1, errors.size());
+ assertEquals("Different node was reported to be duplicate", errors.get(0).id, fooId);
+
+ consistencyCheck.repair(false);
+
+ assertTrue("Index was not repaired properly", searchIndexContainsNode(searchIndex,
fooId));
+ assertTrue("Consistency check still reports errors", searchIndex.runConsistencyCheck().getErrors().isEmpty());
+ }
+
private boolean searchIndexContainsNode(SearchIndex searchIndex, NodeId nodeId) throws
IOException {
final List<Integer> docs = new ArrayList<Integer>(1);
final IndexReader reader = searchIndex.getIndexReader();
|