Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (revision 1798795) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (working copy) @@ -1385,8 +1385,19 @@ int depth = PathUtils.getDepth(path); for (int i = 1; i <= depth && beforeState != null; i++) { String p = PathUtils.getAncestorPath(path, depth - i); - PathRev key = new PathRev(p, beforeState.getLastRevision()); + RevisionVector lastRev = beforeState.getLastRevision(); + PathRev key = new PathRev(p, lastRev); beforeState = nodeCache.getIfPresent(key); + if (missing.equals(beforeState)) { + // This is unexpected. The before state should exist. + // Invalidate the relevant cache entries. (OAK-6294) + LOG.warn("Before state is missing {}. Invalidating " + + "affected cache entries.", key.asString()); + store.invalidateCache(NODES, Utils.getIdFromPath(p)); + nodeCache.invalidate(key); + nodeChildrenCache.invalidate(childNodeCacheKey(path, lastRev, null)); + beforeState = null; + } } DocumentNodeState.Children children = null; if (beforeState != null) { Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (revision 1798795) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (working copy) @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.oak.plugins.document; +import static java.util.Collections.emptyList; import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; @@ -3058,6 +3059,25 @@ } } + // OAK-6294 + @Test + public void missingLastRevInApplyChanges() throws CommitFailedException { + DocumentNodeStore ns = builderProvider.newBuilder().getNodeStore(); + DocumentNodeState root = ns.getRoot(); + + RevisionVector before = root.getLastRevision(); + Revision rev = ns.newRevision(); + RevisionVector after = new RevisionVector(ns.newRevision()); + + String path = "/foo"; + ns.getNode(path, before); + assertNotNull(ns.getNodeCache().getIfPresent(new PathRev(path, before))); + + ns.applyChanges(before, after, rev, path, false, + emptyList(), emptyList(), emptyList()); + assertNull(ns.getNodeCache().getIfPresent(new PathRev(path, before))); + } + private static class WriteCountingStore extends MemoryDocumentStore { private final ThreadLocal createMulti = new ThreadLocal<>(); int count;