You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2007/08/29 12:12:07 UTC

svn commit: r570736 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java

Author: dpfister
Date: Wed Aug 29 03:12:04 2007
New Revision: 570736

URL: http://svn.apache.org/viewvc?rev=570736&view=rev
Log:
JCR-1082 - cache getting out of sync with transientstore causes pathnotfoundexception

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java?rev=570736&r1=570735&r2=570736&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Wed Aug 29 03:12:04 2007
@@ -375,35 +375,47 @@
     /**
      * {@inheritDoc}
      * <p/>
-     * Generate subsequent add and remove notifications for every replacement. This method
-     * currently assumes that the reordering is detectable by comparing the state's child
-     * node entries to the overlayed state's child node entries. It is not able to handle
-     * a transient reordering and will therefore evict its cached entry if such a situation
-     * is detected.
+     * Iterate over all cached children of this state and verify each
+     * child's position.
      */
     public void nodesReplaced(NodeState state) {
-        List entries = state.getReorderedChildNodeEntries();
-        if (entries.size() == 0) {
-            synchronized (cacheMonitor) {
-                if (idCache.containsKey(state.getNodeId())) {
-                    evict(state.getNodeId());
+        synchronized (cacheMonitor) {
+            LRUEntry entry = (LRUEntry) idCache.get(state.getNodeId());
+            if (entry != null) {
+                PathMap.Element element = entry.getElement();
+                Iterator iter = element.getChildren();
+                while (iter.hasNext()) {
+                    PathMap.Element child = (PathMap.Element) iter.next();
+                    LRUEntry childEntry = (LRUEntry) child.get();
+                    if (childEntry == null) {
+                        /**
+                         * Child has no associated UUID information: we're
+                         * therefore unable to determine if this child's
+                         * position is still accurate and have to assume
+                         * the worst and remove it.
+                         */
+                        child.remove(false);
+                        remove(child);
+                        continue;
+                    }
+                    NodeId childId = childEntry.getId();
+                    NodeState.ChildNodeEntry cne = state.getChildNodeEntry(childId);
+                    if (cne == null) {
+                        /* Child no longer in parent node state, so remove it */
+                        child.remove(false);
+                        remove(child);
+                        continue;
+                    }
+                    if (!cne.getName().equals(child.getName()) ||
+                            cne.getIndex() != child.getNormalizedIndex()) {
+                        /* Child still exists but at a different position */
+                        element.move(child.getPathElement(),
+                                Path.PathElement.create(cne.getName(), cne.getIndex()));
+                        continue;
+                    }
+                    /* At this point the child's position is still valid */
                 }
             }
-            return;
-        }
-        Iterator iter = entries.iterator();
-        while (iter.hasNext()) {
-            NodeState.ChildNodeEntry now = (NodeState.ChildNodeEntry) iter.next();
-            NodeState.ChildNodeEntry old =
-                    ((NodeState) state.getOverlayedState()).getChildNodeEntry(now.getId());
-
-            if (old == null) {
-                log.warn("Reordered child node not found in old list.");
-                continue;
-            }
-
-            nodeAdded(state, now.getName(), now.getIndex(), now.getId());
-            nodeRemoved(state, old.getName(), old.getIndex(), old.getId());
         }
     }
 
@@ -486,23 +498,6 @@
         synchronized (cacheMonitor) {
             if (idCache.get(id) != null) {
                 return;
-            }
-
-            /**
-             * Do not cache paths to elements if the parent is transient, since
-             * children may be reordered multiple times (see JCR-993). If a
-             * child's position is cached at some intermediate stage but the
-             * total reordering effectively leaves the child at its initial
-             * position, the child's bad position is hardly detectable.
-             */
-            try {
-                NodeId parentId = state.getParentId();
-                if (parentId != null && provider.getItemState(parentId).isTransient()) {
-                    return;
-                }
-            } catch (ItemStateException e) {
-                String msg = "Unable to retrieve parent state of: " + id;
-                log.warn(msg, e);
             }
 
             if (idCache.size() >= upperLimit) {

Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java?rev=570736&r1=570735&r2=570736&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/PathMap.java Wed Aug 29 03:12:04 2007
@@ -264,22 +264,28 @@
          * @return removed child, may be <code>null</code>
          */
         public Element remove(Path.PathElement nameIndex) {
-            return remove(nameIndex, true);
+            return remove(nameIndex, true, true);
         }
 
         /**
          * Remove a child. If <code>shift</code> is set to <code>true</code>,
          * will shift all children having an index greater than the child
-         * removed to the left. If there are no more children left in
+         * removed to the left. If <code>removeIfEmpty</code> is set to
+         * <code>true</code> and there are no more children left in
          * this element and no object is associated with this element, the
          * element itself gets removed.
          *
          * @param nameIndex child's path element
          * @param shift whether to shift same name siblings having a greater
          *              index to the left
+         * @param removeIfEmpty remove this element itself if it contains
+         *                      no more children and is not associated to
+         *                      an element
          * @return removed child, may be <code>null</code>
          */
-        private Element remove(Path.PathElement nameIndex, boolean shift) {
+        private Element remove(Path.PathElement nameIndex, boolean shift,
+                               boolean removeIfEmpty) {
+
             // convert 1-based index value to 0-base value
             int index = getZeroBasedIndex(nameIndex);
             if (children == null) {
@@ -303,8 +309,8 @@
                 element.parent = null;
                 childrenCount--;
             }
-            if (childrenCount == 0 && obj == null && parent != null) {
-                parent.remove(getPathElement(), shift);
+            if (removeIfEmpty && childrenCount == 0 && obj == null && parent != null) {
+                parent.remove(getPathElement(), shift, true);
             }
             return element;
         }
@@ -323,7 +329,7 @@
          */
         public void remove(boolean shift) {
             if (parent != null) {
-                parent.remove(getPathElement(), shift);
+                parent.remove(getPathElement(), shift, true);
             } else {
                 // Removing the root node is not possible: if it has become
                 // invalid, remove all its children and the associated object
@@ -342,8 +348,28 @@
             childrenCount = 0;
 
             if (obj == null && parent != null) {
-                parent.remove(getPathElement(), false);
+                parent.remove(getPathElement(), false, true);
+            }
+        }
+
+        /**
+         * Move a child of this element to a different location inside the
+         * same parent.
+         *
+         * @param oldNameIndex old name/index 
+         * @param newNameIndex new name/index
+         * @return <code>true</code> if the element was successfully moved;
+         *         otherwise <code>false</code>
+         */
+        public boolean move(Path.PathElement oldNameIndex, 
+                            Path.PathElement newNameIndex) {
+            
+            Element child = remove(oldNameIndex, false, false);
+            if (child != null) {
+                put(newNameIndex, child);
+                return true;
             }
+            return false;
         }
 
         /**
@@ -362,7 +388,7 @@
             this.obj = obj;
 
             if (obj == null && childrenCount == 0 && parent != null) {
-                parent.remove(getPathElement(), false);
+                parent.remove(getPathElement(), false, true);
             }
         }