You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2017/06/15 13:37:17 UTC

svn commit: r1798834 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java

Author: mreutegg
Date: Thu Jun 15 13:37:17 2017
New Revision: 1798834

URL: http://svn.apache.org/viewvc?rev=1798834&view=rev
Log:
OAK-6351: Invalidate cache entries when getChildNodes() is aborted

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1798834&r1=1798833&r2=1798834&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Thu Jun 15 13:37:17 2017
@@ -1284,20 +1284,16 @@ public final class DocumentNodeStore
                 String p = concat(parent.getPath(), input);
                 DocumentNodeState result = getNode(p, readRevision);
                 if (result == null) {
-                    //This is very unexpected situation - parent's child list declares the child to exist, while
-                    //its node state is null. Let's put some extra effort to do some logging
+                    // This is very unexpected situation - parent's child list
+                    // declares the child to exist, while its node state is
+                    // null. Let's put some extra effort to do some logging
+                    // and invalidate the affected cache entries.
                     String id = Utils.getIdFromPath(p);
-                    String cachedDocStr, uncachedDocStr;
-                    try {
-                        cachedDocStr = store.find(Collection.NODES, id).asString();
-                    } catch (DocumentStoreException dse) {
-                        cachedDocStr = dse.toString();
-                    }
-                    try {
-                        uncachedDocStr = store.find(Collection.NODES, id, 0).asString();
-                    } catch (DocumentStoreException dse) {
-                        uncachedDocStr = dse.toString();
-                    }
+                    String cachedDocStr = docAsString(id, true);
+                    String uncachedDocStr = docAsString(id, false);
+                    nodeCache.invalidate(new PathRev(p, readRevision));
+                    nodeChildrenCache.invalidate(childNodeCacheKey(
+                            parent.getPath(), readRevision, name));
                     String exceptionMsg = String.format(
                             "Aborting getChildNodes() - DocumentNodeState is null for %s at %s " +
                                     "{\"cachedDoc\":{%s}, \"uncachedDoc\":{%s}}",
@@ -1307,6 +1303,24 @@ public final class DocumentNodeStore
                 return result.withRootRevision(parent.getRootRevision(),
                         parent.isFromExternalChange());
             }
+
+            private String docAsString(String id, boolean cached) {
+                try {
+                    NodeDocument doc;
+                    if (cached) {
+                        doc = store.find(Collection.NODES, id);
+                    } else {
+                        doc = store.find(Collection.NODES, id, 0);
+                    }
+                    if (doc == null) {
+                        return "<null>";
+                    } else {
+                        return doc.asString();
+                    }
+                } catch (DocumentStoreException e) {
+                    return e.toString();
+                }
+            }
         });
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1798834&r1=1798833&r2=1798834&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java Thu Jun 15 13:37:17 2017
@@ -3078,6 +3078,43 @@ public class DocumentNodeStoreTest {
         assertNull(ns.getNodeCache().getIfPresent(new PathRev(path, before)));
     }
 
+    // OAK-6351
+    @Test
+    public void inconsistentNodeChildrenCache() throws Exception {
+        DocumentNodeStore ns = builderProvider.newBuilder().getNodeStore();
+        NodeBuilder builder = ns.getRoot().builder();
+        builder.child("a");
+        builder.child("b");
+        merge(ns, builder);
+        builder = ns.getRoot().builder();
+        builder.child("b").remove();
+        merge(ns, builder);
+        RevisionVector head = ns.getHeadRevision();
+
+        // simulate an incorrect cache entry
+        PathRev key = new PathRev("/", head);
+        DocumentNodeState.Children c = new DocumentNodeState.Children();
+        c.children.add("a");
+        c.children.add("b");
+        ns.getNodeChildrenCache().put(key, c);
+
+        try {
+            for (ChildNodeEntry entry : ns.getRoot().getChildNodeEntries()) {
+                entry.getName();
+            }
+            fail("must fail with DocumentStoreException");
+        } catch (DocumentStoreException e) {
+            // expected
+        }
+        // next attempt must succeed
+        List<String> names = Lists.newArrayList();
+        for (ChildNodeEntry entry : ns.getRoot().getChildNodeEntries()) {
+            names.add(entry.getName());
+        }
+        assertEquals(1L, names.size());
+        assertTrue(names.contains("a"));
+    }
+
     private static class WriteCountingStore extends MemoryDocumentStore {
         private final ThreadLocal<Boolean> createMulti = new ThreadLocal<>();
         int count;