Return-Path: X-Original-To: apmail-jackrabbit-commits-archive@www.apache.org Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C74A39FE9 for ; Tue, 11 Oct 2011 13:34:39 +0000 (UTC) Received: (qmail 90771 invoked by uid 500); 11 Oct 2011 13:34:39 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 90743 invoked by uid 500); 11 Oct 2011 13:34:39 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 90736 invoked by uid 99); 11 Oct 2011 13:34:39 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 11 Oct 2011 13:34:39 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 11 Oct 2011 13:34:33 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D66C82388900; Tue, 11 Oct 2011 13:34:11 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1181777 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/persistence/check/ main/java/org/apache/jackrabbit/core/persistence/pool/ test/java/org/apache/jackrabbit/core/ test/java/org/apache/jackrabbit/core/p... Date: Tue, 11 Oct 2011 13:34:11 -0000 To: commits@jackrabbit.apache.org From: reschke@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111011133411.D66C82388900@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: reschke Date: Tue Oct 11 13:34:10 2011 New Revision: 1181777 URL: http://svn.apache.org/viewvc?rev=1181777&view=rev Log: JCR-3069: add new ConsistencyChecker interface, implement it in BundleDbPersistenceManager, use it in ConcurrentImportTest, extend AutoFixCorruptNode to check it (work-in-progress) Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyChecker.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReport.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReportImpl.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItem.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItemImpl.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentImportTest.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestHelper.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyChecker.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyChecker.java?rev=1181777&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyChecker.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyChecker.java Tue Oct 11 13:34:10 2011 @@ -0,0 +1,49 @@ +/* + * 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.check; + +import javax.jcr.RepositoryException; + +/** + * Optional interface for Persistence Managers. Allows running consistency + * checks similar to the base one (see @link + * {@link PersistenceManager#checkConsistency(String[], boolean, boolean)) but + * providing a result that can be acted upon. + *

+ * Beware: this interface is designed for unit tests only. + */ +public interface ConsistencyChecker { + + /** + * Perform a consistency check of the data. An example are non-existent + * nodes referenced in a child node entry. The existence of this feature and + * the scope of the implementation can vary in different PersistenceManager + * implementations. + * + * @param uuids + * list of UUIDs of nodes to be checked. if null, all nodes will + * be checked + * @param recursive + * if true, the tree(s) below the given node(s) will be traversed + * and checked as well + * @param fix + * if true, any problems found that can be repaired will be + * repaired. if false, no data will be modified, instead all + * inconsistencies will only get logged + */ + ConsistencyReport check(String[] uuids, boolean recursive, boolean fix) throws RepositoryException; +} Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReport.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReport.java?rev=1181777&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReport.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReport.java Tue Oct 11 13:34:10 2011 @@ -0,0 +1,40 @@ +/* + * 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.check; + +import java.util.Set; + +/** + * Returned as result of a {@link ConsistencyChecker} run. + */ +public interface ConsistencyReport { + + /** + * @return number of nodes that were checked + */ + public int getNodeCount(); + + /** + * @return elapsed time in ms + */ + public long getElapsedTimeMs(); + + /** + * @return generated messages + */ + public Set getItems(); +} \ No newline at end of file Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReportImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReportImpl.java?rev=1181777&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReportImpl.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ConsistencyReportImpl.java Tue Oct 11 13:34:10 2011 @@ -0,0 +1,51 @@ +/* + * 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.check; + +import java.util.Set; + +public class ConsistencyReportImpl implements ConsistencyReport { + + private final int nodeCount; + private final long elapsedTimeMs; + private final Set reports; + + public ConsistencyReportImpl(int nodeCount, long elapsedTimeMs, + Set reports) { + this.nodeCount = nodeCount; + this.elapsedTimeMs = elapsedTimeMs; + this.reports = reports; + } + + public int getNodeCount() { + return nodeCount; + } + + public long getElapsedTimeMs() { + return elapsedTimeMs; + } + + public Set getItems() { + return reports; + } + + @Override + public String toString() { + return "elapsedTimeMs " + elapsedTimeMs + ", nodeCount " + nodeCount + + ", reports: " + reports; + } +} Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItem.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItem.java?rev=1181777&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItem.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItem.java Tue Oct 11 13:34:10 2011 @@ -0,0 +1,33 @@ +/* + * 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.check; + +/** + * An item reported inside a {@link ConsistencyChecker.Report}. + */ +public interface ReportItem { + + /** + * @return node id to which the message applies + */ + public String getNodeId(); + + /** + * @return message + */ + public String getMessage(); +} Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItemImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItemImpl.java?rev=1181777&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItemImpl.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/check/ReportItemImpl.java Tue Oct 11 13:34:10 2011 @@ -0,0 +1,41 @@ +/* + * 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.check; + +public class ReportItemImpl implements ReportItem { + + private final String nodeId; + private final String message; + + public ReportItemImpl(String nodeId, String message) { + this.nodeId = nodeId; + this.message = message; + } + + public String getNodeId() { + return nodeId; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return nodeId + " -- " + message; + } +} 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=1181777&r1=1181776&r2=1181777&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 Oct 11 13:34:10 2011 @@ -27,9 +27,11 @@ import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; +import java.util.Set; import javax.jcr.RepositoryException; import javax.sql.DataSource; @@ -42,6 +44,11 @@ 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; @@ -85,7 +92,7 @@ import org.slf4j.LoggerFactory; * */ public class BundleDbPersistenceManager - extends AbstractBundlePersistenceManager implements DatabaseAware { + extends AbstractBundlePersistenceManager implements DatabaseAware, ConsistencyChecker { /** the default logger */ private static Logger log = LoggerFactory.getLogger(BundleDbPersistenceManager.class); @@ -700,6 +707,12 @@ public class BundleDbPersistenceManager return new DbBlobStore(); } + private void addMessage(Set 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. @@ -711,7 +724,8 @@ public class BundleDbPersistenceManager * {@linkplain NodePropBundle bundles} here */ protected void checkBundleConsistency(NodeId id, NodePropBundle bundle, - boolean fix, Collection modifications) { + boolean fix, Collection modifications, + Set reports) { //log.info(name + ": checking bundle '" + id + "'"); // skip all system nodes except root node @@ -732,20 +746,25 @@ public class BundleDbPersistenceManager try { // analyze child node bundles NodePropBundle child = loadBundle(entry.getId()); + String message = null; if (child == null) { - log.error( - "NodeState '" + id + "' references inexistent child" - + " '" + entry.getName() + "' with id " - + "'" + entry.getId() + "'"); + 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) { - log.error("ChildNode has invalid parent uuid: "); + message = "ChildNode has invalid parent uuid: "; + log.error(message); } else if (!cp.equals(id)) { - log.error("ChildNode has invalid parent uuid: '" + cp + "' (instead of '" + id + "')"); + message = "ChildNode has invalid parent uuid: '" + 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) } @@ -764,7 +783,9 @@ public class BundleDbPersistenceManager // skip root nodes (that point to itself) if (parentId != null && !id.toString().endsWith("babecafebabe")) { if (loadBundle(parentId) == null) { - log.error("NodeState '" + id + "' references inexistent parent uuid '" + parentId + "'"); + String message = "NodeState '" + id + "' references inexistent parent uuid '" + parentId + "'"; + log.error(message); + addMessage(reports, id, message); } NodePropBundle parentBundle = loadBundle(parentId); Iterator childNodeIter = parentBundle.getChildNodeEntries().iterator(); @@ -776,29 +797,54 @@ public class BundleDbPersistenceManager break; } } - if (!found) { - log.error("NodeState '" + id + "' is not referenced by its parent node '" + parentId + "'"); - 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); - } + 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) { log.error("Error reading node '" + parentId + "' (parent of '" + id + "'): " + e); } } + public ConsistencyReport check(String[] uuids, boolean recursive, + boolean fix) throws RepositoryException { + + Set reports = new HashSet(); + + 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 reports) throws RepositoryException { int count = 0; int total = 0; Collection modifications = new ArrayList(); if (uuids == null) { - // get all node bundles in the database with a single sql statement, + // get all node bundles in the database with a single SQL statement, // which is (probably) faster than loading each bundle and traversing the tree ResultSet rs = null; try { @@ -806,8 +852,9 @@ public class BundleDbPersistenceManager rs = conHelper.exec(sql, new Object[0], false, 0); try { if (!rs.next()) { - log.error("Could not retrieve total number of bundles. empty result set."); - return; + String message = "Could not retrieve total number of bundles. empty result set."; + log.error(message); + throw new RepositoryException(message); } total = rs.getInt(1); } finally { @@ -838,7 +885,7 @@ public class BundleDbPersistenceManager } // parse and check bundle NodePropBundle bundle = readBundle(id, bRs, 1); - checkBundleConsistency(id, bundle, fix, modifications); + checkBundleConsistency(id, bundle, fix, modifications, reports); } catch (SQLException e) { log.error("Unable to parse bundle " + id, e); } finally { @@ -887,7 +934,7 @@ public class BundleDbPersistenceManager continue; } - checkBundleConsistency(id, bundle, fix, modifications); + checkBundleConsistency(id, bundle, fix, modifications, reports); if (recursive) { for (NodePropBundle.ChildNodeEntry entry : bundle.getChildNodeEntries()) { @@ -923,6 +970,8 @@ public class BundleDbPersistenceManager } log.info(name + ": checked " + count + "/" + total + " bundles."); + + return total; } /** Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentImportTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentImportTest.java?rev=1181777&r1=1181776&r2=1181777&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentImportTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentImportTest.java Tue Oct 11 13:34:10 2011 @@ -27,7 +27,9 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.core.persistence.check.ConsistencyReport; import org.apache.jackrabbit.spi.Name; +import org.apache.jackrabbit.test.NotExecutableException; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; @@ -51,9 +53,14 @@ public class ConcurrentImportTest extend * performed by the threads. */ private static final int NUM_NODES = 10; - + public void testConcurrentImport() throws RepositoryException { - concurrentImport(new String[]{JcrConstants.MIX_REFERENCEABLE}, false); + try { + concurrentImport(new String[]{JcrConstants.MIX_REFERENCEABLE}, false); + } + finally { + checkConsistency(); + } } public void testConcurrentImportSynced() throws RepositoryException { @@ -206,4 +213,12 @@ public class ConcurrentImportTest extend } -} \ No newline at end of file + private void checkConsistency() throws RepositoryException { + try { + ConsistencyReport rep = TestHelper.checkConsistency(testRootNode.getSession()); + assertEquals("Found broken nodes in repository: " + rep, 0, rep.getItems().size()); + } catch (NotExecutableException ex) { + // ignore + } + } +} Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestHelper.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestHelper.java?rev=1181777&r1=1181776&r2=1181777&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestHelper.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestHelper.java Tue Oct 11 13:34:10 2011 @@ -16,7 +16,14 @@ */ package org.apache.jackrabbit.core; +import javax.jcr.Repository; import javax.jcr.RepositoryException; +import javax.jcr.Session; + +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.test.NotExecutableException; /** * TestHelper provides test utility methods. @@ -35,4 +42,31 @@ public class TestHelper { throws RepositoryException { repo.getWorkspaceInfo(name).dispose(); } + + /** + * Runs a consistency check on the workspace used by the specified session. + * + * @param session the Session accessing the workspace to be checked + * @throws RepositoryException if an error occurs while getting the + * workspace with the given name. + * @throws NotExecutableException if the {@link PersistenceManager} does + * not implement {@link ConsistencyChecker}, or if the associated + * {@link Repository} is not a {@link RepositoryImpl}. + */ + public static ConsistencyReport checkConsistency(Session session) + throws NotExecutableException, RepositoryException { + Repository r = session.getRepository(); + if (!(r instanceof RepositoryImpl)) { + throw new NotExecutableException(); + } else { + RepositoryImpl ri = (RepositoryImpl) r; + PersistenceManager pm = ri.getWorkspaceInfo( + session.getWorkspace().getName()).getPersistenceManager(); + if (!(pm instanceof ConsistencyChecker)) { + throw new NotExecutableException(); + } else { + return ((ConsistencyChecker) pm).check(null, true, false); + } + } + } } Modified: 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=1181777&r1=1181776&r2=1181777&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/persistence/AutoFixCorruptNode.java Tue Oct 11 13:34:10 2011 @@ -21,15 +21,20 @@ 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.TestHelper; import org.apache.jackrabbit.core.TransientRepository; +import org.apache.jackrabbit.core.persistence.check.ConsistencyReport; /** * Tests that a corrupt node is automatically fixed. @@ -46,6 +51,51 @@ public class AutoFixCorruptNode extends setUp(); } + /** + * Unit test for JCR-3069 + */ + public void testAutoFixWithConsistencyCheck() 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(); + + s = openSession(rep, false); + try { + ConsistencyReport r = TestHelper.checkConsistency(s); + assertNotNull(r); + assertNotNull(r.getItems()); + assertEquals(1, r.getItems().size()); + assertEquals(test.getIdentifier(), r.getItems().iterator().next() + .getNodeId()); + } finally { + s.logout(); + rep.shutdown(); + FileUtils.deleteDirectory(new File("repository")); + } + + } + public void testAutoFix() throws Exception { // new repository @@ -62,10 +112,10 @@ public class AutoFixCorruptNode extends 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=?"); + 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(); @@ -108,10 +158,13 @@ public class AutoFixCorruptNode extends } - private Session openSession(Repository rep, boolean autoFix) throws RepositoryException { - SimpleCredentials cred = new SimpleCredentials("admin", "admin".toCharArray()); + 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"); + cred.setAttribute("org.apache.jackrabbit.autoFixCorruptions", + "true"); } return rep.login(cred); }