diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java
index 24a1ad3..5776a0c 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/PersistentCacheStatsMBean.java
@@ -42,6 +42,8 @@ public interface PersistentCacheStatsMBean extends CacheStatsMBean {
 
     CompositeData getPutRejectedQueueFullRateHistory();
 
+    CompositeData getPutRejectedAsCachedInSecRateHistory();
+
     CompositeData getInvalidateOneRateHistory();
 
     CompositeData getInvalidateAllRateHistory();
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
index 50d92f7..a72c238 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
@@ -1093,8 +1093,8 @@ public class DocumentMK {
             return buildCache(CacheType.NODE, getNodeCacheSize(), store, null);
         }
 
-        public Cache<PathRev, DocumentNodeState.Children> buildChildrenCache() {
-            return buildCache(CacheType.CHILDREN, getChildrenCacheSize(), null, null);
+        public Cache<PathRev, DocumentNodeState.Children> buildChildrenCache(DocumentNodeStore store) {
+            return buildCache(CacheType.CHILDREN, getChildrenCacheSize(), store, null);
         }
 
         public Cache<PathRev, StringValue> buildMemoryDiffCache() {
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStateCache.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStateCache.java
index d4a0e12..59ef016 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStateCache.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStateCache.java
@@ -30,6 +30,11 @@ public interface DocumentNodeStateCache {
                                                         RevisionVector lastRev) {
             return null;
         }
+
+        @Override
+        public boolean isCached(String path) {
+            return false;
+        }
     };
 
     /**
@@ -45,5 +50,12 @@ public interface DocumentNodeStateCache {
     @CheckForNull
     AbstractDocumentNodeState getDocumentNodeState(String path, RevisionVector rootRevision, RevisionVector lastRev);
 
+    /**
+     * Determines if given path is cached by this implementation
+     * @param path path to check
+     * @return true if given path is cached
+     */
+    boolean isCached(String path);
+
 
 }
diff --git 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
index 912a237..2129d59 100644
--- 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
@@ -487,7 +487,7 @@ public final class DocumentNodeStore
         nodeCacheStats = new CacheStats(nodeCache, "Document-NodeState",
                 builder.getWeigher(), builder.getNodeCacheSize());
 
-        nodeChildrenCache = builder.buildChildrenCache();
+        nodeChildrenCache = builder.buildChildrenCache(this);
         nodeChildrenCacheStats = new CacheStats(nodeChildrenCache, "Document-NodeChildren",
                 builder.getWeigher(), builder.getChildrenCacheSize());
 
@@ -837,10 +837,14 @@ public final class DocumentNodeStore
         return diffCache.getStats();
     }
 
-    Cache<PathRev, DocumentNodeState> getNodeCache() {
+    public Cache<PathRev, DocumentNodeState> getNodeCache() {
         return nodeCache;
     }
 
+    public Cache<PathRev, DocumentNodeState.Children> getNodeChildrenCache() {
+        return nodeChildrenCache;
+    }
+
     /**
      * Returns the journal entry that will be stored in the journal with the
      * next background updated.
@@ -2809,6 +2813,10 @@ public final class DocumentNodeStore
         return nodeStoreStatsCollector;
     }
 
+    public DocumentNodeStateCache getNodeStateCache() {
+        return nodeStateCache;
+    }
+
     public void setNodeStateCache(DocumentNodeStateCache nodeStateCache) {
         this.nodeStateCache = nodeStateCache;
     }
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
index 41c5ebb..9018be7 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
@@ -40,6 +40,10 @@ public final class PathRev implements CacheValue {
         this.revision = checkNotNull(revision);
     }
 
+    public String getPath() {
+        return path;
+    }
+
     @Override
     public int getMemory() {
         return 24                                       // shallow size
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
index b705375..41e4f19 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
@@ -51,6 +51,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) DocumentNodeState.fromString(store, value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return !store.getNodeStateCache().isCached(((PathRev)key).getPath());
+        }
     },
     
     CHILDREN {
@@ -77,6 +81,11 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) DocumentNodeState.Children.fromString(value);
         }
+
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return !store.getNodeStateCache().isCached(((PathRev)key).getPath());
+        }
     }, 
     
     DIFF {
@@ -103,6 +112,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) StringValue.fromString(value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
     },
 
     DOC_CHILDREN {
@@ -129,6 +142,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) NodeDocument.Children.fromString(value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
     }, 
     
     DOCUMENT {
@@ -155,6 +172,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) NodeDocument.fromString(docStore, value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
     },
 
     PREV_DOCUMENT {
@@ -181,6 +202,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) NodeDocument.fromString(docStore, value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
     },
 
     LOCAL_DIFF {
@@ -207,6 +232,10 @@ public enum CacheType {
                 DocumentNodeStore store, DocumentStore docStore, String value) {
             return (V) LocalDiffCache.Diff.fromString(value);
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
     },
     
     BLOB {
@@ -236,6 +265,10 @@ public enum CacheType {
                 DocumentStore docStore, String value) {
             throw new UnsupportedOperationException();
         }
+        @Override
+        public <K> boolean shouldCache(DocumentNodeStore store, K key) {
+            return true;
+        }
         
     };
     
@@ -247,6 +280,7 @@ public enum CacheType {
     public abstract <V> String valueToString(V value);
     public abstract <V> V valueFromString(
             DocumentNodeStore store, DocumentStore docStore, String value);
+    public abstract <K> boolean shouldCache(DocumentNodeStore store, K key);
 
 }
 
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
index f556ac9..33d02d9 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
@@ -22,6 +22,7 @@ import static com.google.common.cache.RemovalCause.SIZE;
 import static java.util.Collections.singleton;
 
 import java.nio.ByteBuffer;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
@@ -64,6 +65,7 @@ class NodeCache<K, V> implements Cache<K, V>, GenerationCache, EvictionListener<
     private final DataType keyType;
     private final DataType valueType;
     private final CacheMetadata<K> memCacheMetadata;
+    private final DocumentNodeStore nodeStore;
     CacheWriteQueue<K, V> writeQueue;
 
     NodeCache(
@@ -77,6 +79,7 @@ class NodeCache<K, V> implements Cache<K, V>, GenerationCache, EvictionListener<
         this.cache = cache;
         this.memCache = memCache;
         this.type = type;
+        this.nodeStore = docNodeStore;
         PersistentCache.LOG.info("wrapping map " + this.type);
         map = new MultiGenerationMap<K, V>();
         keyType = new KeyDataType(type);
@@ -147,6 +150,9 @@ class NodeCache<K, V> implements Cache<K, V>, GenerationCache, EvictionListener<
         if (value == null) {
             map.remove(key);
         } else {
+            if (!type.shouldCache(nodeStore, key)){
+                return;
+            }
             map.put(key, value);
 
             long memory = 0L;
@@ -312,6 +318,9 @@ class NodeCache<K, V> implements Cache<K, V>, GenerationCache, EvictionListener<
             } else if (metadata != null && metadata.getAccessCount() < 1) {
                 qualifiesToPersist = false;
                 stats.markPutRejectedEntryNotUsed();
+            } else if (!type.shouldCache(nodeStore, key)){
+                qualifiesToPersist = false;
+                stats.markPutRejectedAsCachedInSecondary();
             }
 
             if (qualifiesToPersist) {
@@ -332,4 +341,8 @@ class NodeCache<K, V> implements Cache<K, V>, GenerationCache, EvictionListener<
     public PersistentCacheStats getPersistentCacheStats() {
         return stats;
     }
+
+    Map<K, V> getGenerationalMap() {
+        return Collections.unmodifiableMap(map);
+    }
 }
\ No newline at end of file
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java
index dd80bbf..4d3a42a 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCacheStats.java
@@ -22,6 +22,7 @@ import org.apache.jackrabbit.oak.api.jmx.PersistentCacheStatsMBean;
 import org.apache.jackrabbit.oak.commons.IOUtils;
 import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean;
 import org.apache.jackrabbit.oak.stats.CounterStats;
+import org.apache.jackrabbit.oak.stats.Counting;
 import org.apache.jackrabbit.oak.stats.MeterStats;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
 import org.apache.jackrabbit.oak.stats.StatsOptions;
@@ -63,6 +64,7 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
     private static final String PUT_REJECTED_ALREADY_PERSISTED = "PUT_REJECTED_ALREADY_PERSISTED";
     private static final String PUT_REJECTED_ENTRY_NOT_USED = "PUT_REJECTED_ENTRY_NOT_USED";
     private static final String PUT_REJECTED_FULL_QUEUE = "PUT_REJECTED_FULL_QUEUE";
+    private static final String PUT_REJECTED_SECONDARY_CACHE = "PUT_REJECTED_SECONDARY_CACHE";
 
     private final StatisticsProvider statisticsProvider;
     private final String cacheName;
@@ -100,6 +102,9 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
     private final MeterStats putRejectedByFullQueueMeter;
     private final TimeSeries putRejectedByFullQueueHistory;
 
+    private final MeterStats putRejectedAsCachedInSecMeter;
+    private final TimeSeries putRejectedAsCachedInSecHistory;
+
     private final TimerStats readTimer;
 
     private final CounterStats usedSpaceByteCounter;
@@ -202,6 +207,10 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
             putRejectedByFullQueueHistory = StatisticsProvider.NOOP.getStats().getTimeSeries(statName, false);
         }
 
+        statName = getStatName(PUT_REJECTED_SECONDARY_CACHE, cacheName);
+        putRejectedAsCachedInSecMeter = statisticsProvider.getMeter(statName, StatsOptions.DEFAULT);
+        putRejectedAsCachedInSecHistory = getTimeSeries(statName);
+
         diskStats = new UsedSpaceTracker(usedSpaceByteCounter);
     }
 
@@ -243,6 +252,10 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
         putRejectedEntryNotUsedMeter.mark();
     }
 
+    public void markPutRejectedAsCachedInSecondary() {
+        putRejectedAsCachedInSecMeter.mark();
+    }
+
     public void markPutRejectedQueueFull() {
         putRejectedByFullQueueMeter.mark();
     }
@@ -410,6 +423,12 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
     }
 
     @Override
+    public CompositeData getPutRejectedAsCachedInSecRateHistory() {
+        return TimeSeriesStatsUtil.asCompositeData(putRejectedAsCachedInSecHistory, "Persistent cache put rejected " +
+                "(entry is covered by secondary)");
+    }
+
+    @Override
     public CompositeData getInvalidateOneRateHistory() {
         return TimeSeriesStatsUtil.asCompositeData(invalidateOneRateHistory, "Persistent cache invalidate one entry");
     }
@@ -475,6 +494,9 @@ public class PersistentCacheStats extends AnnotatedStandardMBean implements Pers
         // ignored
     }
 
+    Counting getPutRejectedAsCachedInSecCounter() {
+        return putRejectedAsCachedInSecMeter;
+    }
 
     //~--------------------------------------< private helpers
 
diff --git oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCache.java oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCache.java
index 3525e30..dca4a2b 100644
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCache.java
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCache.java
@@ -116,6 +116,11 @@ class SecondaryStoreCache implements DocumentNodeStateCache, SecondaryStoreRootO
         return null;
     }
 
+    @Override
+    public boolean isCached(String path) {
+        return pathFilter.filter(path) == PathFilter.Result.INCLUDE;
+    }
+
     @CheckForNull
     private AbstractDocumentNodeState findByMatchingLastRev(AbstractDocumentNodeState root, String path,
                                                       RevisionVector lastRev){
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AsyncCacheTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AsyncCacheTest.java
index f40ec74..c99af18 100644
--- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AsyncCacheTest.java
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AsyncCacheTest.java
@@ -21,18 +21,23 @@ import java.io.File;
 import com.google.common.cache.Cache;
 
 import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
 import org.junit.Test;
 
 import static org.junit.Assert.assertNull;
 
 public class AsyncCacheTest {
 
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
+
     @Test
     public void invalidateWhileInQueue() throws Exception {
         FileUtils.deleteDirectory(new File("target/cacheTest"));
-        DocumentMK.Builder builder = new DocumentMK.Builder();
+        DocumentMK.Builder builder = builderProvider.newBuilder();
         builder.setPersistentCache("target/cacheTest");
-        Cache<PathRev, DocumentNodeState.Children> cache = builder.buildChildrenCache();
+        DocumentNodeStore nodeStore = builder.getNodeStore();
+        Cache<PathRev, DocumentNodeState.Children> cache = builder.buildChildrenCache(nodeStore);
         DocumentNodeState.Children c = new DocumentNodeState.Children();
         for (int i = 0; i < 100; i++) {
             c.children.add("node-" + i);
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/AsyncQueueTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/AsyncQueueTest.java
index a4bba04..2ab27e5 100644
--- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/AsyncQueueTest.java
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/AsyncQueueTest.java
@@ -21,6 +21,7 @@ package org.apache.jackrabbit.oak.plugins.document.persistentCache;
 import com.google.common.cache.RemovalCause;
 import org.apache.commons.io.FileUtils;
 import org.apache.jackrabbit.oak.cache.CacheLIRS;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
 import org.apache.jackrabbit.oak.plugins.document.PathRev;
 import org.apache.jackrabbit.oak.plugins.document.Revision;
 import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
@@ -28,6 +29,7 @@ import org.apache.jackrabbit.oak.plugins.document.persistentCache.async.CacheWri
 import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import javax.annotation.Nonnull;
@@ -44,6 +46,9 @@ import static org.junit.Assert.assertEquals;
 
 public class AsyncQueueTest {
 
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
+
     private static final StringValue VAL = new StringValue("xyz");
 
     private PersistentCache pCache;
@@ -69,12 +74,14 @@ public class AsyncQueueTest {
                 }
             }
         }).build();
-        nodeCache = (NodeCache<PathRev, StringValue>) pCache.wrap(null, null, cache, CacheType.NODE);
+        nodeCache = (NodeCache<PathRev, StringValue>) pCache.wrap(builderProvider.newBuilder().getNodeStore(),
+                null, cache,  CacheType.NODE);
         nodeCacheRef.set(nodeCache);
 
         CacheWriteQueueWrapper writeQueue = new CacheWriteQueueWrapper(nodeCache.writeQueue);
         nodeCache.writeQueue = writeQueue;
 
+
         this.putActions = writeQueue.putActions;
         this.invalidateActions = writeQueue.invalidateActions;
         this.id = 0;
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCacheTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCacheTest.java
new file mode 100644
index 0000000..a7a0977
--- /dev/null
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCacheTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.oak.plugins.document.persistentCache;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import com.google.common.cache.RemovalCause;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.apache.jackrabbit.oak.plugins.document.AbstractDocumentNodeState;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStateCache;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.PathRev;
+import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.stats.Counting;
+import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class NodeCacheTest {
+
+    @Rule
+    public final TemporaryFolder tempFolder = new TemporaryFolder(new File("target"));
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
+    private DocumentNodeStore ns;
+    private NodeCache<PathRev, DocumentNodeState> nodeCache;
+    private NodeCache<PathRev, DocumentNodeState.Children> nodeChildren;
+    private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+    private StatisticsProvider statsProvider = new DefaultStatisticsProvider(executor);
+
+    @After
+    public void shutDown(){
+        new ExecutorCloser(executor).close();
+    }
+
+    @Test
+    public void testAsyncCache() throws Exception{
+        initializeNodeStore(true);
+        ns.setNodeStateCache(new PathExcludingCache("/c"));
+
+        NodeBuilder builder = ns.getRoot().builder();
+        builder.child("a").child("b");
+        builder.child("c").child("d");
+        AbstractDocumentNodeState root = (AbstractDocumentNodeState) ns.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        PathRev prc = new PathRev("/c", root.getRootRevision());
+        PathRev pra = new PathRev("/a", root.getRootRevision());
+        Counting counter = nodeCache.getPersistentCacheStats().getPutRejectedAsCachedInSecCounter();
+        long count0 = counter.getCount();
+
+        //Adding this should be rejected
+        nodeCache.evicted(prc, (DocumentNodeState) root.getChildNode("c"), RemovalCause.SIZE);
+        long count1 = counter.getCount();
+        assertTrue(count1 > count0);
+
+        //Adding this should NOT be rejected
+        nodeCache.evicted(pra, (DocumentNodeState) root.getChildNode("a"), RemovalCause.SIZE);
+        long count2 = counter.getCount();
+        assertEquals(count1 , count2);
+    }
+
+    @Test
+    public void testSyncCachePut() throws Exception {
+        initializeNodeStore(false);
+        NodeBuilder builder = ns.getRoot().builder();
+        builder.child("a").child("b");
+        ns.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        //Do a read again
+        ns.getRoot().getChildNode("a").getChildNode("b");
+
+        assertContains(nodeCache, "/a/b");
+        assertContains(nodeCache, "/a");
+        assertContains(nodeChildren, "/a");
+
+        ns.setNodeStateCache(new PathExcludingCache("/c"));
+
+        builder = ns.getRoot().builder();
+        builder.child("c").child("d");
+        ns.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        ns.getRoot().getChildNode("c").getChildNode("d");
+        assertNotContains(nodeCache, "/c/d");
+        assertNotContains(nodeCache, "/c");
+        assertNotContains(nodeChildren, "/c");
+    }
+
+    private void initializeNodeStore(boolean asyncCache) {
+        DocumentMK.Builder builder = builderProvider.newBuilder()
+                .setAsyncDelay(0)
+                .setStatisticsProvider(statsProvider);
+
+        if (asyncCache){
+            builder.setPersistentCache("target/persistentCache,time,+async");
+        }else {
+            builder.setPersistentCache("target/persistentCache,time");
+        }
+        ns = builder.getNodeStore();
+        nodeCache = (NodeCache<PathRev, DocumentNodeState>) ns.getNodeCache();
+        nodeChildren = (NodeCache<PathRev, DocumentNodeState.Children>) ns.getNodeChildrenCache();
+    }
+
+
+    private static <V> void assertContains(NodeCache<PathRev, V> cache, String path) {
+        assertPathRevs(cache, path, true);
+    }
+
+    private static <V> void assertNotContains(NodeCache<PathRev, V> cache, String path) {
+        assertPathRevs(cache, path, false);
+    }
+
+    private static <V> void assertPathRevs(NodeCache<PathRev, V> cache, String path, boolean contains) {
+        List<PathRev> revs = getPathRevs(cache, path);
+        List<PathRev> matchingRevs = Lists.newArrayList();
+        for (PathRev pr : revs) {
+            if (cache.getGenerationalMap().containsKey(pr)) {
+                matchingRevs.add(pr);
+            }
+        }
+
+        if (contains && matchingRevs.isEmpty()) {
+            fail(String.format("Expecting entry for [%s]. Did not found in %s", path, matchingRevs));
+        }
+
+        if (!contains && !matchingRevs.isEmpty()) {
+            fail(String.format("Expecting entry for [%s]. Found %s", path, revs));
+        }
+    }
+
+    private static <V> List<PathRev> getPathRevs(NodeCache<PathRev, V> cache, String path) {
+        List<PathRev> revs = Lists.newArrayList();
+        for (PathRev pr : cache.asMap().keySet()) {
+            if (pr.getPath().equals(path)) {
+                revs.add(pr);
+            }
+        }
+        return revs;
+    }
+
+    private static class PathExcludingCache implements DocumentNodeStateCache {
+        private final String excludeRoot;
+
+        private PathExcludingCache(String excludeRoot) {
+            this.excludeRoot = excludeRoot;
+        }
+
+        @Override
+        public AbstractDocumentNodeState getDocumentNodeState(String path, RevisionVector rootRevision,
+                                                              RevisionVector lastRev) {
+            return null;
+        }
+
+        @Override
+        public boolean isCached(String path) {
+            if (path.startsWith(excludeRoot)) {
+                return true;
+            }
+            return false;
+        }
+    };
+}
\ No newline at end of file
diff --git oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCacheTest.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCacheTest.java
index f3a1863..5674b08 100644
--- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCacheTest.java
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/secondary/SecondaryStoreCacheTest.java
@@ -46,6 +46,7 @@ import static com.google.common.collect.ImmutableList.of;
 import static org.apache.jackrabbit.oak.plugins.document.secondary.SecondaryStoreObserverTest.create;
 import static org.apache.jackrabbit.oak.plugins.document.secondary.SecondaryStoreObserverTest.documentState;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -198,6 +199,15 @@ public class SecondaryStoreCacheTest {
         assertNull(result);
     }
 
+    @Test
+    public void isCached() throws Exception{
+        SecondaryStoreCache cache = createCache(new PathFilter(of("/a"), empty));
+
+        assertTrue(cache.isCached("/a"));
+        assertTrue(cache.isCached("/a/b"));
+        assertFalse(cache.isCached("/x"));
+    }
+
     private SecondaryStoreCache createCache(PathFilter pathFilter){
         SecondaryStoreBuilder builder = createBuilder(pathFilter);
         SecondaryStoreCache cache = builder.buildCache();
