On 2018-03-16 13:32, Fabián Mandelbaum wrote:
Hello, the saga continues... I've wrote a small robot to traverse the versions storage and find the unreferenced version histories (actually, it finds all nt:versionHistory nodes whose jcr:versionableUuid point to a non-stored-anymore node). Using an old-but-still-working-at-least-with-JR-2.6 Java GUI tool to browse and manipulate the repository, I've deleted some versionable nodes to create the orphans.

The full code (minus the copyright) for the robot is this:

package com.calenco.core.robot;

import com.calenco.storage.PooledRepoManager;
import java.util.TimerTask;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.jackrabbit.JcrConstants;
import org.apache.log4j.Logger;

/**
  *
  * Task that will periodically check orphaned revision history nodes
 * (nt:versionHistory) on the jcr:versionStorage tree and delete the orphans
  * found. Ideally, it should not find any orphan... but V3.1 and previous
 * Calenco versions left some orphaned revision history nodes on certain Eraser
  * extension operations.
  *
  * @author fabman
  */
public class JcrHistoryCleanerTimerTask extends TimerTask {

    public static final Logger LOG = Logger.getLogger(JcrHistoryCleanerTimerTask.class);     private static final PooledRepoManager REPOMGR = PooledRepoManager.getInstance();

     public JcrHistoryCleanerTimerTask() {
         super();
     }

     @Override
     public void run() {
         LOG.info(String.format("%s running...", getClass()));
         Session nsession = null;
         try {
             nsession = REPOMGR.getSessionRW();
            processNode(nsession, nsession.getNode("/jcr:system/jcr:versionStorage"));
             if (nsession.hasPendingChanges()) {
                 nsession.save();
             }
         } catch (RepositoryException ex) {
            LOG.warn(String.format("Got %s while trying to clean revision history tree", ex), ex);
         } finally {
             REPOMGR.releaseSessionRW(nsession);
         }
     }

    private void processNode(Session nsession, Node node) throws RepositoryException {
         String npath = node.getPath();
         String ntype = node.getPrimaryNodeType().getName();
        LOG.info(String.format("Processing node %s [%s]...", npath, ntype));
         if (null == ntype) {
            LOG.warn(String.format("!!! Skipping node %s of type %s", npath, ntype));
         } else {
             switch (ntype) {
                 case "rep:versionStorage":
                     // recurse...
                     NodeIterator nit = node.getNodes();
                     while (nit.hasNext()) {
                         processNode(nsession, nit.nextNode());
                     }
                     break;
                 case JcrConstants.NT_VERSIONHISTORY:
                    String vuuid = node.getProperty(JcrConstants.JCR_VERSIONABLEUUID).getString();
                     if (!nodeExists(nsession, vuuid)) {
                         node.remove();
                        LOG.info(String.format(">>> Node with UUID %s is not stored anymore... its revision history has been deleted...", vuuid));
                     }
                     break;
                 default:
                    LOG.warn(String.format("!!! Skipping node %s of type %s", npath, ntype));
                     break;
             }
         }
     }

     private boolean nodeExists(Session nsession, String uuid) {
         try {
             nsession.getNodeByIdentifier(uuid);
             return true;
         } catch (ItemNotFoundException ignoredReturningFalse) {
             return false;
         } catch (RepositoryException ex) {
            LOG.warn(String.format("!!! Got unexpected %s while checking if node with UUID %s exists", ex.getMessage(), uuid));
             return false;
         }
     }
}

When the robot is run, I get this on the log:

2018-03-16 08:43:06,444INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:42 - class com.calenco.core.robot.JcrHistoryCleanerTimerTask running...

2018-03-16 08:43:06,445INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage [rep:versionStorage]...

2018-03-16 08:43:06,448INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78 [rep:versionStorage]...

2018-03-16 08:43:06,449INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/11 [rep:versionStorage]...

2018-03-16 08:43:06,451INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/11/fe [rep:versionStorage]...

2018-03-16 08:43:06,454INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/11/fe/7811fe34-0aae-432a-9015-2626ee77bced [nt:versionHistory]...

2018-03-16 08:43:06,457INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/da [rep:versionStorage]...

2018-03-16 08:43:06,459INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/da/be [rep:versionStorage]...

2018-03-16 08:43:06,460INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/78/da/be/78dabe1c-ead8-414d-8455-4ece9412c1a6 [nt:versionHistory]...


[LOTS_OF_RECURSIVE_TRAVERSAL_RELATED_STUFF_REMOVED_FROM_HERE]


2018-03-16 08:43:06,737INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/e9 [rep:versionStorage]...

2018-03-16 08:43:06,739INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/e9/07 [rep:versionStorage]...

2018-03-16 08:43:06,739INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/e9/07/ed [rep:versionStorage]...

2018-03-16 08:43:06,740INFO com.calenco.core.robot.JcrHistoryCleanerTimerTask:60 - Processing node /jcr:system/jcr:versionStorage/e9/07/ed/e907edad-ad75-4572-ba44-56a9f5741fb9 [nt:versionHistory]...

2018-03-16 08:43:06,743WARN com.calenco.core.robot.JcrHistoryCleanerTimerTask:51 - Got javax.jcr.nodetype.ConstraintViolationException: Unable to perform operation. Node is protected. while trying to clean revision history tree

javax.jcr.nodetype.ConstraintViolationException: Unable to perform operation. Node is protected.

at org.apache.jackrabbit.core.ItemValidator.checkCondition(ItemValidator.java:276)

at org.apache.jackrabbit.core.ItemValidator.checkRemove(ItemValidator.java:254)

at org.apache.jackrabbit.core.ItemRemoveOperation.perform(ItemRemoveOperation.java:63)

at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:200)

at org.apache.jackrabbit.core.ItemImpl.perform(ItemImpl.java:91)

at org.apache.jackrabbit.core.ItemImpl.remove(ItemImpl.java:322)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.processNode(JcrHistoryCleanerTimerTask.java:75)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.processNode(JcrHistoryCleanerTimerTask.java:69)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.processNode(JcrHistoryCleanerTimerTask.java:69)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.processNode(JcrHistoryCleanerTimerTask.java:69)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.processNode(JcrHistoryCleanerTimerTask.java:69)

at com.calenco.core.robot.JcrHistoryCleanerTimerTask.run(JcrHistoryCleanerTimerTask.java:46)

at java.util.TimerThread.mainLoop(Timer.java:555)

at java.util.TimerThread.run(Timer.java:505)


I've removed lots of log entries for nodes that don't need processing so you don't have to scroll down that much to get to the interesting part. The removed entries are basically the recursive traversal of the revision history tree nodes. Version storage for node with UUID e907edad-ad75-4572-ba44-56a9f5741fb9 is an orphan, there's no such node stored anymore.

So, it seems that (soundly, but won't let me remove what I need) the tree under /jcr:system/jcr:versionStorage is protected in a way that some of the "regular" node manipulation API (node.remove()) cannot be used on those nodes.
...

What type of node are you trying to delete? The version history node?

Best regards, Julian

Reply via email to