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/12/20 19:49:46 UTC
svn commit: r1221428 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence:
./ bundle/ mem/ pool/
Author: reschke
Date: Tue Dec 20 18:49:46 2011
New Revision: 1221428
URL: http://svn.apache.org/viewvc?rev=1221428&view=rev
Log:
JCR-3185: refactor consistency checks in BundleDBPersistenceManager into a standalone class that could be re-used for other PMs
Added:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ConsistencyCheckerImpl.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/IterablePersistenceManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemBundlePersistenceManager.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/IterablePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/IterablePersistenceManager.java?rev=1221428&r1=1221427&r2=1221428&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/IterablePersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/IterablePersistenceManager.java Tue Dec 20 18:49:46 2011
@@ -16,6 +16,8 @@
*/
package org.apache.jackrabbit.core.persistence;
+import java.util.List;
+
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.state.ItemStateException;
@@ -37,11 +39,11 @@ public interface IterablePersistenceMana
*
* @param after the lower limit, or null for no limit.
* @param maxCount the maximum number of node ids to return, or 0 for no limit.
- * @return an iterator of all bundles.
+ * @return a list of all bundles.
* @throws ItemStateException if an error while loading occurs.
* @throws RepositoryException if a repository exception occurs
*/
- Iterable<NodeId> getAllNodeIds(NodeId after, int maxCount)
+ List<NodeId> getAllNodeIds(NodeId after, int maxCount)
throws ItemStateException, RepositoryException;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java?rev=1221428&r1=1221427&r2=1221428&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java Tue Dec 20 18:49:46 2011
@@ -26,6 +26,7 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
import org.apache.jackrabbit.api.stats.RepositoryStatistics;
import org.apache.jackrabbit.core.cache.Cache;
@@ -40,6 +41,8 @@ import org.apache.jackrabbit.core.persis
import org.apache.jackrabbit.core.persistence.IterablePersistenceManager;
import org.apache.jackrabbit.core.persistence.PMContext;
import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyChecker;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
import org.apache.jackrabbit.core.persistence.util.BLOBStore;
import org.apache.jackrabbit.core.persistence.util.FileBasedIndex;
import org.apache.jackrabbit.core.persistence.util.NodePropBundle;
@@ -87,7 +90,7 @@ import org.slf4j.LoggerFactory;
* </ul>
*/
public abstract class AbstractBundlePersistenceManager implements
- PersistenceManager, CachingPersistenceManager, IterablePersistenceManager, CacheAccessListener {
+ PersistenceManager, CachingPersistenceManager, IterablePersistenceManager, CacheAccessListener, ConsistencyChecker {
/** the default logger */
private static Logger log = LoggerFactory.getLogger(AbstractBundlePersistenceManager.class);
@@ -777,11 +780,23 @@ public abstract class AbstractBundlePers
}
/**
- * This implementation does nothing.
- *
* {@inheritDoc}
*/
public void checkConsistency(String[] uuids, boolean recursive, boolean fix) {
+ try {
+ ConsistencyCheckerImpl cs = new ConsistencyCheckerImpl(this);
+ cs.check(uuids, recursive, fix);
+ } catch (RepositoryException ex) {
+ log.error("While running consistency check.", ex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConsistencyReport check(String[] uuids, boolean recursive, boolean fix) throws RepositoryException {
+ ConsistencyCheckerImpl cs = new ConsistencyCheckerImpl(this);
+ return cs.check(uuids, recursive, fix);
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java?rev=1221428&r1=1221427&r2=1221428&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java Tue Dec 20 18:49:46 2011
@@ -42,6 +42,7 @@ import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* This is a generic persistence manager that stores the {@link NodePropBundle}s
@@ -482,7 +483,7 @@ public class BundleFsPersistenceManager
/**
* {@inheritDoc}
*/
- public Iterable<NodeId> getAllNodeIds(NodeId bigger, int maxCount)
+ public List<NodeId> getAllNodeIds(NodeId bigger, int maxCount)
throws ItemStateException {
ArrayList<NodeId> list = new ArrayList<NodeId>();
try {
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ConsistencyCheckerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ConsistencyCheckerImpl.java?rev=1221428&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ConsistencyCheckerImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ConsistencyCheckerImpl.java Tue Dec 20 18:49:46 2011
@@ -0,0 +1,282 @@
+/*
+ * 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.bundle;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyChecker;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyReportImpl;
+import org.apache.jackrabbit.core.persistence.check.ReportItem;
+import org.apache.jackrabbit.core.persistence.check.ReportItemImpl;
+import org.apache.jackrabbit.core.persistence.util.NodePropBundle;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConsistencyCheckerImpl implements ConsistencyChecker {
+
+ /** the default logger */
+ private static Logger log = LoggerFactory.getLogger(ConsistencyCheckerImpl.class);
+
+ private AbstractBundlePersistenceManager pm;
+
+ public ConsistencyCheckerImpl(AbstractBundlePersistenceManager pm) {
+ this.pm = pm;
+ }
+
+ public ConsistencyReport check(String[] uuids, boolean recursive, boolean fix) throws RepositoryException {
+ Set<ReportItem> reports = new HashSet<ReportItem>();
+
+ long tstart = System.currentTimeMillis();
+ int total = internalCheckConsistency(uuids, recursive, fix, reports);
+ long elapsed = System.currentTimeMillis() - tstart;
+
+ return new ConsistencyReportImpl(total, elapsed, reports);
+ }
+
+ private int internalCheckConsistency(String[] uuids, boolean recursive, boolean fix, Set<ReportItem> reports) throws RepositoryException {
+ int count = 0;
+ int total = 0;
+ Collection<NodePropBundle> modifications = new ArrayList<NodePropBundle>();
+
+ if (uuids == null) {
+ try {
+ List<NodeId> allIds = pm.getAllNodeIds(null, 0);
+ total = allIds.size();
+
+ for (NodeId id : allIds) {
+ try {
+ // parse and check bundle
+ NodePropBundle bundle = pm.loadBundle(id);
+ if (bundle == null) {
+ log.error("No bundle found for id '" + id + "'");
+ } else {
+ checkBundleConsistency(id, bundle, fix, modifications, reports);
+
+ count++;
+ if (count % 1000 == 0) {
+ log.info(pm + ": checked " + count + "/" + (total == -1 ? "?" : total) + " bundles...");
+ }
+ }
+ } catch (ItemStateException e) {
+ // problem already logged (loadBundle called with
+ // logDetailedErrors=true)
+ }
+
+ }
+ } catch (ItemStateException ex) {
+ throw new RepositoryException("getting nodeIds", ex);
+ } finally {
+ total = count;
+ }
+ } else {
+ // check only given uuids, handle recursive flag
+
+ // 1) convert uuid array to modifiable list
+ // 2) for each uuid do
+ // a) load node bundle
+ // b) check bundle, store any bundle-to-be-modified in collection
+ // c) if recursive, add child uuids to list of uuids
+
+ List<NodeId> idList = new ArrayList<NodeId>(uuids.length);
+ // convert uuid string array to list of UUID objects
+ for (int i = 0; i < uuids.length; i++) {
+ try {
+ idList.add(new NodeId(uuids[i]));
+ } catch (IllegalArgumentException e) {
+ log.error("Invalid id for consistency check, skipping: '" + uuids[i] + "': " + e);
+ }
+ }
+
+ // iterate over UUIDs (including ones that are newly added inside the loop!)
+ for (int i = 0; i < idList.size(); i++) {
+ NodeId id = idList.get(i);
+ try {
+ // load the node from the database
+ NodePropBundle bundle = pm.loadBundle(id);
+
+ if (bundle == null) {
+ log.error("No bundle found for id '" + id + "'");
+ }
+ else {
+ checkBundleConsistency(id, bundle, fix, modifications, reports);
+
+ if (recursive) {
+ for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
+ idList.add(entry.getId());
+ }
+ }
+
+ count++;
+ if (count % 1000 == 0) {
+ log.info(pm + ": checked " + count + "/" + idList.size() + " bundles...");
+ }
+ }
+ } catch (ItemStateException e) {
+ // problem already logged (loadBundle called with logDetailedErrors=true)
+ }
+ }
+
+ total = idList.size();
+ }
+
+ // repair collected broken bundles
+ if (fix && !modifications.isEmpty()) {
+ log.info(pm + ": Fixing " + modifications.size() + " inconsistent bundle(s)...");
+ for (NodePropBundle bundle : modifications) {
+ try {
+ log.info(pm + ": Fixing bundle '" + bundle.getId() + "'");
+ bundle.markOld(); // use UPDATE instead of INSERT
+ pm.storeBundle(bundle);
+ pm.evictBundle(bundle.getId());
+ } catch (ItemStateException e) {
+ log.error(pm + ": Error storing fixed bundle: " + e);
+ }
+ }
+ }
+
+ log.info(pm + ": checked " + count + "/" + total + " bundles.");
+
+ return total;
+ }
+
+ /**
+ * Checks a single bundle for inconsistencies, ie. inexistent child nodes
+ * and inexistent parents.
+ *
+ * @param id node id for the bundle to check
+ * @param bundle the bundle to check
+ * @param fix if <code>true</code>, repair things that can be repaired
+ * @param modifications if <code>fix == true</code>, collect the repaired
+ * {@linkplain NodePropBundle bundles} here
+ */
+ private void checkBundleConsistency(NodeId id, NodePropBundle bundle,
+ boolean fix, Collection<NodePropBundle> modifications,
+ Set<ReportItem> reports) {
+ //log.info(name + ": checking bundle '" + id + "'");
+
+ // skip all system nodes except root node
+ if (id.toString().endsWith("babecafebabe")
+ && !id.toString().equals("cafebabe-cafe-babe-cafe-babecafebabe")) {
+ return;
+ }
+
+ // look at the node's children
+ Collection<NodePropBundle.ChildNodeEntry> missingChildren = new ArrayList<NodePropBundle.ChildNodeEntry>();
+ for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
+
+ // skip check for system nodes (root, system root, version storage, node types)
+ if (entry.getId().toString().endsWith("babecafebabe")) {
+ continue;
+ }
+
+ try {
+ // analyze child node bundles
+ NodePropBundle child = pm.loadBundle(entry.getId());
+ String message = null;
+ if (child == null) {
+ message = "NodeState '" + id + "' references inexistent child" + " '"
+ + entry.getName() + "' with id " + "'" + entry.getId() + "'";
+ log.error(message);
+ missingChildren.add(entry);
+ } else {
+ NodeId cp = child.getParentId();
+ if (cp == null) {
+ message = "ChildNode has invalid parent id: <null>";
+ log.error(message);
+ } else if (!cp.equals(id)) {
+ message = "ChildNode has invalid parent id: '" + cp + "' (instead of '" + id + "')";
+ log.error(message);
+ }
+ }
+ if (message != null) {
+ addMessage(reports, id, message);
+ }
+ } catch (ItemStateException e) {
+ // problem already logged (loadBundle called with logDetailedErrors=true)
+ addMessage(reports, id, e.getMessage());
+ }
+ }
+ // remove child node entry (if fixing is enabled)
+ if (fix && !missingChildren.isEmpty()) {
+ for (NodePropBundle.ChildNodeEntry entry : missingChildren) {
+ bundle.getChildNodeEntries().remove(entry);
+ }
+ modifications.add(bundle);
+ }
+
+ // check parent reference
+ NodeId parentId = bundle.getParentId();
+ try {
+ // skip root nodes (that point to itself)
+ if (parentId != null && !id.toString().endsWith("babecafebabe")) {
+ NodePropBundle parentBundle = pm.loadBundle(parentId);
+
+ if (parentBundle == null) {
+ String message = "NodeState '" + id + "' references inexistent parent id '" + parentId + "'";
+ log.error(message);
+ addMessage(reports, id, message);
+ }
+ else {
+ boolean found = false;
+
+ for (NodePropBundle.ChildNodeEntry entry : parentBundle.getChildNodeEntries()) {
+ if (entry.getId().equals(id)){
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ String message = "NodeState '" + id + "' is not referenced by its parent node '" + parentId + "'";
+ log.error(message);
+ addMessage(reports, id, message);
+
+ int l = (int) System.currentTimeMillis();
+ int r = new Random().nextInt();
+ int n = l + r;
+ String nodeName = Integer.toHexString(n);
+ parentBundle.addChildNodeEntry(NameFactoryImpl
+ .getInstance().create("{}" + nodeName), id);
+ log.info("NodeState '" + id + "' adds itself to its parent node '" + parentId + "' with a new name '" + nodeName + "'");
+ modifications.add(parentBundle);
+ }
+ }
+ }
+ } catch (ItemStateException e) {
+ String message = "Error reading node '" + parentId + "' (parent of '" + id + "'): " + e;
+ log.error(message);
+ addMessage(reports, id, message);
+ }
+ }
+
+ private void addMessage(Set<ReportItem> reports, NodeId id, String message) {
+ if (reports != null) {
+ reports.add(new ReportItemImpl(id.toString(), message));
+ }
+ }
+}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemBundlePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemBundlePersistenceManager.java?rev=1221428&r1=1221427&r2=1221428&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemBundlePersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemBundlePersistenceManager.java Tue Dec 20 18:49:46 2011
@@ -25,7 +25,9 @@ import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.jcr.RepositoryException;
@@ -489,9 +491,11 @@ public class InMemBundlePersistenceManag
/**
* {@inheritDoc}
*/
- public Iterable<NodeId> getAllNodeIds(NodeId after, int maxCount) throws ItemStateException, RepositoryException {
+ public List<NodeId> getAllNodeIds(NodeId after, int maxCount) throws ItemStateException, RepositoryException {
// ignore after and count parameters.
- return bundleStore.keySet();
+ List<NodeId> result = new ArrayList<NodeId>();
+ result.addAll(bundleStore.keySet());
+ return result;
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java?rev=1221428&r1=1221427&r2=1221428&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java Tue Dec 20 18:49:46 2011
@@ -26,11 +26,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
-import java.util.Random;
-import java.util.Set;
import javax.jcr.RepositoryException;
import javax.sql.DataSource;
@@ -43,11 +39,6 @@ import org.apache.jackrabbit.core.id.Nod
import org.apache.jackrabbit.core.id.PropertyId;
import org.apache.jackrabbit.core.persistence.PMContext;
import org.apache.jackrabbit.core.persistence.bundle.AbstractBundlePersistenceManager;
-import org.apache.jackrabbit.core.persistence.check.ConsistencyChecker;
-import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
-import org.apache.jackrabbit.core.persistence.check.ConsistencyReportImpl;
-import org.apache.jackrabbit.core.persistence.check.ReportItem;
-import org.apache.jackrabbit.core.persistence.check.ReportItemImpl;
import org.apache.jackrabbit.core.persistence.util.BLOBStore;
import org.apache.jackrabbit.core.persistence.util.BundleBinding;
import org.apache.jackrabbit.core.persistence.util.ErrorHandling;
@@ -65,7 +56,6 @@ import org.apache.jackrabbit.core.util.d
import org.apache.jackrabbit.core.util.db.DatabaseAware;
import org.apache.jackrabbit.core.util.db.DbUtility;
import org.apache.jackrabbit.core.util.db.StreamWrapper;
-import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -91,7 +81,7 @@ import org.slf4j.LoggerFactory;
* </ul>
*/
public class BundleDbPersistenceManager
- extends AbstractBundlePersistenceManager implements DatabaseAware, ConsistencyChecker {
+ extends AbstractBundlePersistenceManager implements DatabaseAware {
/** the default logger */
private static Logger log = LoggerFactory.getLogger(BundleDbPersistenceManager.class);
@@ -706,250 +696,6 @@ public class BundleDbPersistenceManager
return new DbBlobStore();
}
- private void addMessage(Set<ReportItem> reports, NodeId id, String message) {
- if (reports != null) {
- reports.add(new ReportItemImpl(id.toString(), message));
- }
- }
-
- /**
- * Checks a single bundle for inconsistencies, ie. inexistent child nodes
- * and inexistent parents.
- *
- * @param id node id for the bundle to check
- * @param bundle the bundle to check
- * @param fix if <code>true</code>, repair things that can be repaired
- * @param modifications if <code>fix == true</code>, collect the repaired
- * {@linkplain NodePropBundle bundles} here
- */
- protected void checkBundleConsistency(NodeId id, NodePropBundle bundle,
- boolean fix, Collection<NodePropBundle> modifications,
- Set<ReportItem> reports) {
- //log.info(name + ": checking bundle '" + id + "'");
-
- // skip all system nodes except root node
- if (id.toString().endsWith("babecafebabe")
- && !id.toString().equals("cafebabe-cafe-babe-cafe-babecafebabe")) {
- return;
- }
-
- // look at the node's children
- Collection<NodePropBundle.ChildNodeEntry> missingChildren = new ArrayList<NodePropBundle.ChildNodeEntry>();
- for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
-
- // skip check for system nodes (root, system root, version storage, node types)
- if (entry.getId().toString().endsWith("babecafebabe")) {
- continue;
- }
-
- try {
- // analyze child node bundles
- NodePropBundle child = loadBundle(entry.getId());
- String message = null;
- if (child == null) {
- message = "NodeState '" + id + "' references inexistent child" + " '"
- + entry.getName() + "' with id " + "'" + entry.getId() + "'";
- log.error(message);
- missingChildren.add(entry);
- } else {
- NodeId cp = child.getParentId();
- if (cp == null) {
- message = "ChildNode has invalid parent id: <null>";
- log.error(message);
- } else if (!cp.equals(id)) {
- message = "ChildNode has invalid parent id: '" + cp + "' (instead of '" + id + "')";
- log.error(message);
- }
- }
- if (message != null) {
- addMessage(reports, id, message);
- }
- } catch (ItemStateException e) {
- // problem already logged (loadBundle called with logDetailedErrors=true)
- addMessage(reports, id, e.getMessage());
- }
- }
- // remove child node entry (if fixing is enabled)
- if (fix && !missingChildren.isEmpty()) {
- for (NodePropBundle.ChildNodeEntry entry : missingChildren) {
- bundle.getChildNodeEntries().remove(entry);
- }
- modifications.add(bundle);
- }
-
- // check parent reference
- NodeId parentId = bundle.getParentId();
- try {
- // skip root nodes (that point to itself)
- if (parentId != null && !id.toString().endsWith("babecafebabe")) {
- NodePropBundle parentBundle = loadBundle(parentId);
-
- if (parentBundle == null) {
- String message = "NodeState '" + id + "' references inexistent parent id '" + parentId + "'";
- log.error(message);
- addMessage(reports, id, message);
- }
- else {
- boolean found = false;
-
- for (NodePropBundle.ChildNodeEntry entry : parentBundle.getChildNodeEntries()) {
- if (entry.getId().equals(id)){
- found = true;
- break;
- }
- }
-
- if (!found) {
- String message = "NodeState '" + id + "' is not referenced by its parent node '" + parentId + "'";
- log.error(message);
- addMessage(reports, id, message);
-
- int l = (int) System.currentTimeMillis();
- int r = new Random().nextInt();
- int n = l + r;
- String nodeName = Integer.toHexString(n);
- parentBundle.addChildNodeEntry(NameFactoryImpl
- .getInstance().create("{}" + nodeName), id);
- log.info("NodeState '" + id + "' adds itself to its parent node '" + parentId + "' with a new name '" + nodeName + "'");
- modifications.add(parentBundle);
- }
- }
- }
- } catch (ItemStateException e) {
- String message = "Error reading node '" + parentId + "' (parent of '" + id + "'): " + e;
- log.error(message);
- addMessage(reports, id, message);
- }
- }
-
- public ConsistencyReport check(String[] uuids, boolean recursive,
- boolean fix) throws RepositoryException {
-
- Set<ReportItem> reports = new HashSet<ReportItem>();
-
- long tstart = System.currentTimeMillis();
- int total = internalCheckConsistency(uuids, recursive, fix, reports);
- long elapsed = System.currentTimeMillis() - tstart;
-
- return new ConsistencyReportImpl(total, elapsed, reports);
- }
-
- public void checkConsistency(String[] uuids, boolean recursive, boolean fix) {
- try {
- internalCheckConsistency(uuids, recursive, fix, null);
- }
- catch (RepositoryException ex) {
- log.error("While running consistency check.", ex);
- }
- }
-
- private int internalCheckConsistency(String[] uuids, boolean recursive, boolean fix, Set<ReportItem> reports) throws RepositoryException {
- int count = 0;
- int total = 0;
- Collection<NodePropBundle> modifications = new ArrayList<NodePropBundle>();
-
- if (uuids == null) {
- total = getNumberOfNodeIds();
-
- try {
- Iterable<NodeId> allIds = getAllNodeIds(null, 0);
-
- for (NodeId id : allIds) {
- try {
- // parse and check bundle
- NodePropBundle bundle = loadBundle(id);
- if (bundle == null) {
- log.error("No bundle found for id '" + id + "'");
- } else {
- checkBundleConsistency(id, bundle, fix, modifications, reports);
-
- count++;
- if (count % 1000 == 0) {
- log.info(name + ": checked " + count + "/" + total + " bundles...");
- }
- }
- } catch (ItemStateException e) {
- // problem already logged (loadBundle called with
- // logDetailedErrors=true)
- }
-
- }
- } catch (ItemStateException ex) {
- throw new RepositoryException("getting nodeIds", ex);
- } finally {
- total = count;
- }
- } else {
- // check only given uuids, handle recursive flag
-
- // 1) convert uuid array to modifiable list
- // 2) for each uuid do
- // a) load node bundle
- // b) check bundle, store any bundle-to-be-modified in collection
- // c) if recursive, add child uuids to list of uuids
-
- List<NodeId> idList = new ArrayList<NodeId>(uuids.length);
- // convert uuid string array to list of UUID objects
- for (int i = 0; i < uuids.length; i++) {
- try {
- idList.add(new NodeId(uuids[i]));
- } catch (IllegalArgumentException e) {
- log.error("Invalid id for consistency check, skipping: '" + uuids[i] + "': " + e);
- }
- }
-
- // iterate over UUIDs (including ones that are newly added inside the loop!)
- for (int i = 0; i < idList.size(); i++) {
- NodeId id = idList.get(i);
- try {
- // load the node from the database
- NodePropBundle bundle = loadBundle(id);
-
- if (bundle == null) {
- log.error("No bundle found for id '" + id + "'");
- }
- else {
- checkBundleConsistency(id, bundle, fix, modifications, reports);
-
- if (recursive) {
- for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) {
- idList.add(entry.getId());
- }
- }
-
- count++;
- if (count % 1000 == 0) {
- log.info(name + ": checked " + count + "/" + idList.size() + " bundles...");
- }
- }
- } catch (ItemStateException e) {
- // problem already logged (loadBundle called with logDetailedErrors=true)
- }
- }
-
- total = idList.size();
- }
-
- // repair collected broken bundles
- if (fix && !modifications.isEmpty()) {
- log.info(name + ": Fixing " + modifications.size() + " inconsistent bundle(s)...");
- for (NodePropBundle bundle : modifications) {
- try {
- log.info(name + ": Fixing bundle '" + bundle.getId() + "'");
- bundle.markOld(); // use UPDATE instead of INSERT
- storeBundle(bundle);
- evictBundle(bundle.getId());
- } catch (ItemStateException e) {
- log.error(name + ": Error storing fixed bundle: " + e);
- }
- }
- }
-
- log.info(name + ": checked " + count + "/" + total + " bundles.");
-
- return total;
- }
-
/**
* {@inheritDoc}
*/
@@ -1020,29 +766,10 @@ public class BundleDbPersistenceManager
return params.toArray();
}
- private synchronized int getNumberOfNodeIds() throws RepositoryException {
- ResultSet rs = null;
- try {
- String sql = "select count(*) from " + schemaObjectPrefix + "BUNDLE";
- rs = conHelper.exec(sql, new Object[0], false, 0);
-
- if (!rs.next()) {
- String message = "Could not retrieve total number of bundles: empty result set.";
- log.error(message);
- throw new RepositoryException(message);
- }
- return rs.getInt(1);
- } catch (SQLException ex) {
- throw new RepositoryException("Could not retrieve total number of bundles", ex);
- } finally {
- DbUtility.close(rs);
- }
- }
-
/**
* {@inheritDoc}
*/
- public synchronized Iterable<NodeId> getAllNodeIds(NodeId bigger, int maxCount)
+ public synchronized List<NodeId> getAllNodeIds(NodeId bigger, int maxCount)
throws ItemStateException, RepositoryException {
ResultSet rs = null;
try {