Author: catholicon
Date: Fri Jan 29 02:53:12 2016
New Revision: 1727470

URL: http://svn.apache.org/viewvc?rev=1727470&view=rev
Log:
OAK-3066: Persistent cache for previous documents

NodeDocumentCache wraps both classes of cache (leaf-level-split-docs and 
others).
Added a test cases verifying statistics according to how loads should work. A 
minor test for check for split level leaf docs as well.
Update documentation according to available configs and a brief about 
difference between the 2 cases of node docs

Added:
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/cache/NodeDocumentCache.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
    
jackrabbit/oak/trunk/oak-core/src/main/resources/OSGI-INF/metatype/metatype.properties
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractMongoConnectionTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/CacheInvalidationIT.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/JournalIT.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
    jackrabbit/oak/trunk/oak-doc/src/site/markdown/nodestore/documentmk.md
    jackrabbit/oak/trunk/oak-doc/src/site/markdown/osgi_config.md

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 Fri Jan 29 02:53:12 2016
@@ -487,6 +487,7 @@ public class DocumentMK {
     public static class Builder {
         private static final long DEFAULT_MEMORY_CACHE_SIZE = 256 * 1024 * 
1024;
         public static final int DEFAULT_NODE_CACHE_PERCENTAGE = 25;
+        public static final int DEFAULT_PREV_DOC_CACHE_PERCENTAGE = 4;
         public static final int DEFAULT_CHILDREN_CACHE_PERCENTAGE = 10;
         public static final int DEFAULT_DIFF_CACHE_PERCENTAGE = 5;
         public static final int DEFAULT_DOC_CHILDREN_CACHE_PERCENTAGE = 3;
@@ -504,6 +505,7 @@ public class DocumentMK {
         private Weigher<CacheValue, CacheValue> weigher = new 
EmpiricalWeigher();
         private long memoryCacheSize = DEFAULT_MEMORY_CACHE_SIZE;
         private int nodeCachePercentage = DEFAULT_NODE_CACHE_PERCENTAGE;
+        private int prevDocCachePercentage = DEFAULT_PREV_DOC_CACHE_PERCENTAGE;
         private int childrenCachePercentage = 
DEFAULT_CHILDREN_CACHE_PERCENTAGE;
         private int diffCachePercentage = DEFAULT_DIFF_CACHE_PERCENTAGE;
         private int docChildrenCachePercentage = 
DEFAULT_DOC_CHILDREN_CACHE_PERCENTAGE;
@@ -799,16 +801,19 @@ public class DocumentMK {
         }
         
         public Builder memoryCacheDistribution(int nodeCachePercentage,
+                                               int prevDocCachePercentage,
                                                int childrenCachePercentage,
                                                int docChildrenCachePercentage,
                                                int diffCachePercentage) {
             checkArgument(nodeCachePercentage >= 0);
+            checkArgument(prevDocCachePercentage >= 0);
             checkArgument(childrenCachePercentage>= 0);
             checkArgument(docChildrenCachePercentage >= 0);
             checkArgument(diffCachePercentage >= 0);
-            checkArgument(nodeCachePercentage + childrenCachePercentage + 
+            checkArgument(nodeCachePercentage + prevDocCachePercentage + 
childrenCachePercentage +
                     docChildrenCachePercentage + diffCachePercentage < 100);
             this.nodeCachePercentage = nodeCachePercentage;
+            this.prevDocCachePercentage = prevDocCachePercentage;
             this.childrenCachePercentage = childrenCachePercentage;
             this.docChildrenCachePercentage = docChildrenCachePercentage;
             this.diffCachePercentage = diffCachePercentage;
@@ -819,12 +824,16 @@ public class DocumentMK {
             return memoryCacheSize * nodeCachePercentage / 100;
         }
 
+        public long getPrevDocumentCacheSize() {
+            return memoryCacheSize * prevDocCachePercentage / 100;
+        }
+
         public long getChildrenCacheSize() {
             return memoryCacheSize * childrenCachePercentage / 100;
         }
 
         public long getDocumentCacheSize() {
-            return memoryCacheSize - getNodeCacheSize() - 
getChildrenCacheSize() 
+            return memoryCacheSize - getNodeCacheSize() - 
getPrevDocumentCacheSize() - getChildrenCacheSize()
                     - getDiffCacheSize() - getDocChildrenCacheSize();
         }
 
@@ -985,10 +994,18 @@ public class DocumentMK {
             return buildCache(CacheType.DOCUMENT, getDocumentCacheSize(), 
null, docStore);
         }
 
+        public Cache<StringValue, NodeDocument> 
buildPrevDocumentsCache(DocumentStore docStore) {
+            return buildCache(CacheType.PREV_DOCUMENT, 
getPrevDocumentCacheSize(), null, docStore);
+        }
+
         public NodeDocumentCache buildNodeDocumentCache(DocumentStore 
docStore, NodeDocumentLocks locks) {
-            Cache<CacheValue, NodeDocument> cache = 
buildDocumentCache(docStore);
-            CacheStats cacheStats = new CacheStats(cache, 
"Document-Documents", getWeigher(), getDocumentCacheSize());
-            return new NodeDocumentCache(cache, cacheStats, locks);
+            Cache<CacheValue, NodeDocument> nodeDocumentsCache = 
buildDocumentCache(docStore);
+            CacheStats nodeDocumentsCacheStats = new 
CacheStats(nodeDocumentsCache, "Document-Documents", getWeigher(), 
getDocumentCacheSize());
+
+            Cache<StringValue, NodeDocument> prevDocumentsCache = 
buildPrevDocumentsCache(docStore);
+            CacheStats prevDocumentsCacheStats = new 
CacheStats(prevDocumentsCache, "Document-PrevDocuments", getWeigher(), 
getPrevDocumentCacheSize());
+
+            return new NodeDocumentCache(nodeDocumentsCache, 
nodeDocumentsCacheStats, prevDocumentsCache, prevDocumentsCacheStats, locks);
         }
 
         private <K extends CacheValue, V extends CacheValue> Cache<K, V> 
buildCache(

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 Fri Jan 29 02:53:12 2016
@@ -27,6 +27,7 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_DIFF_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_DOC_CHILDREN_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_NODE_CACHE_PERCENTAGE;
+import static 
org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder.DEFAULT_PREV_DOC_CACHE_PERCENTAGE;
 import static 
org.apache.jackrabbit.oak.spi.blob.osgi.SplitBlobStoreService.ONLY_STANDALONE_TARGET;
 import static 
org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
 
@@ -143,13 +144,19 @@ public class DocumentNodeStoreService {
             description = "Cache size in MB. This is distributed among various 
caches used in DocumentNodeStore"
     )
     private static final String PROP_CACHE = "cache";
-    
+
     @Property(intValue = DEFAULT_NODE_CACHE_PERCENTAGE,
             label = "NodeState Cache",
             description = "Percentage of cache to be allocated towards Node 
cache"
     )
     private static final String PROP_NODE_CACHE_PERCENTAGE = 
"nodeCachePercentage";
-    
+
+    @Property(intValue = DEFAULT_PREV_DOC_CACHE_PERCENTAGE,
+            label = "PreviousDocument Cache",
+            description = "Percentage of cache to be allocated towards 
Previous Document cache"
+    )
+    private static final String PROP_PREV_DOC_CACHE_PERCENTAGE = 
"prevDocCachePercentage";
+
     @Property(intValue = DocumentMK.Builder.DEFAULT_CHILDREN_CACHE_PERCENTAGE,
             label = "NodeState Children Cache",
             description = "Percentage of cache to be allocated towards 
Children cache"
@@ -361,6 +368,7 @@ public class DocumentNodeStoreService {
 
         int cacheSize = toInteger(prop(PROP_CACHE), DEFAULT_CACHE);
         int nodeCachePercentage = toInteger(prop(PROP_NODE_CACHE_PERCENTAGE), 
DEFAULT_NODE_CACHE_PERCENTAGE);
+        int prevDocCachePercentage = 
toInteger(prop(PROP_PREV_DOC_CACHE_PERCENTAGE), DEFAULT_NODE_CACHE_PERCENTAGE);
         int childrenCachePercentage = 
toInteger(prop(PROP_CHILDREN_CACHE_PERCENTAGE), 
DEFAULT_CHILDREN_CACHE_PERCENTAGE);
         int docChildrenCachePercentage = 
toInteger(prop(PROP_DOC_CHILDREN_CACHE_PERCENTAGE), 
DEFAULT_DOC_CHILDREN_CACHE_PERCENTAGE);
         int diffCachePercentage = toInteger(prop(PROP_DIFF_CACHE_PERCENTAGE), 
DEFAULT_DIFF_CACHE_PERCENTAGE);
@@ -373,7 +381,8 @@ public class DocumentNodeStoreService {
                 setStatisticsProvider(statisticsProvider).
                 memoryCacheSize(cacheSize * MB).
                 memoryCacheDistribution(
-                        nodeCachePercentage, 
+                        nodeCachePercentage,
+                        prevDocCachePercentage,
                         childrenCachePercentage, 
                         docChildrenCachePercentage, 
                         diffCachePercentage).
@@ -615,13 +624,15 @@ public class DocumentNodeStoreService {
         }
         DocumentStore ds = store.getDocumentStore();
         if (ds.getCacheStats() != null) {
-            registrations.add(
-                    registerMBean(whiteboard,
-                            CacheStatsMBean.class,
-                            ds.getCacheStats(),
-                            CacheStatsMBean.TYPE,
-                            ds.getCacheStats().getName())
-            );
+            for (CacheStats cacheStats : ds.getCacheStats()) {
+                registrations.add(
+                        registerMBean(whiteboard,
+                                CacheStatsMBean.class,
+                                cacheStats,
+                                CacheStatsMBean.TYPE,
+                                cacheStats.getName())
+                );
+            }
         }
 
         registrations.add(

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
 Fri Jan 29 02:53:12 2016
@@ -329,7 +329,7 @@ public interface DocumentStore {
      * @return status information about the cache
      */
     @CheckForNull
-    CacheStats getCacheStats();
+    Iterable<CacheStats> getCacheStats();
 
     /**
      * @return description of the underlying storage.

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/cache/NodeDocumentCache.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/cache/NodeDocumentCache.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/cache/NodeDocumentCache.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/cache/NodeDocumentCache.java
 Fri Jan 29 02:53:12 2016
@@ -28,6 +28,8 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
 
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.apache.jackrabbit.oak.cache.CacheValue;
 import org.apache.jackrabbit.oak.plugins.document.Document;
@@ -38,22 +40,36 @@ import org.apache.jackrabbit.oak.plugins
 import com.google.common.base.Objects;
 import com.google.common.cache.Cache;
 
+import static 
org.apache.jackrabbit.oak.plugins.document.util.Utils.isLeafPreviousDocId;
+
 /**
  * Cache for the NodeDocuments. This class is thread-safe and uses the 
provided NodeDocumentLock.
  */
 public class NodeDocumentCache implements Closeable {
 
-    private final Cache<CacheValue, NodeDocument> nodesCache;
+    private final Cache<CacheValue, NodeDocument> nodeDocumentsCache;
+
+    private final CacheStats nodeDocumentsCacheStats;
 
-    private final CacheStats cacheStats;
+    /**
+     * The previous documents cache
+     *
+     * Key: StringValue, value: NodeDocument
+     */
+    private final Cache<StringValue, NodeDocument> prevDocumentsCache;
+    private final CacheStats prevDocumentsCacheStats;
 
     private final NodeDocumentLocks locks;
 
-    public NodeDocumentCache(@Nonnull Cache<CacheValue, NodeDocument> 
nodesCache,
-                             @Nonnull CacheStats cacheStats,
+    public NodeDocumentCache(@Nonnull Cache<CacheValue, NodeDocument> 
nodeDocumentsCache,
+                             @Nonnull CacheStats nodeDocumentsCacheStats,
+                             @Nonnull Cache<StringValue, NodeDocument> 
prevDocumentsCache,
+                             @Nonnull CacheStats prevDocumentsCacheStats,
                              @Nonnull NodeDocumentLocks locks) {
-        this.nodesCache = nodesCache;
-        this.cacheStats = cacheStats;
+        this.nodeDocumentsCache = nodeDocumentsCache;
+        this.nodeDocumentsCacheStats = nodeDocumentsCacheStats;
+        this.prevDocumentsCache = prevDocumentsCache;
+        this.prevDocumentsCacheStats = prevDocumentsCacheStats;
         this.locks = locks;
     }
 
@@ -65,7 +81,11 @@ public class NodeDocumentCache implement
     public void invalidate(@Nonnull String key) {
         Lock lock = locks.acquire(key);
         try {
-            nodesCache.invalidate(new StringValue(key));
+            if (isLeafPreviousDocId(key)) {
+                prevDocumentsCache.invalidate(new StringValue(key));
+            } else {
+                nodeDocumentsCache.invalidate(new StringValue(key));
+            }
         } finally {
             lock.unlock();
         }
@@ -104,7 +124,11 @@ public class NodeDocumentCache implement
      */
     @CheckForNull
     public NodeDocument getIfPresent(@Nonnull String key) {
-        return nodesCache.getIfPresent(new StringValue(key));
+        if (isLeafPreviousDocId(key)) {
+            return prevDocumentsCache.getIfPresent(new StringValue(key));
+        } else {
+            return nodeDocumentsCache.getIfPresent(new StringValue(key));
+        }
     }
 
     /**
@@ -119,7 +143,11 @@ public class NodeDocumentCache implement
     @Nonnull
     public NodeDocument get(@Nonnull String key, @Nonnull 
Callable<NodeDocument> valueLoader)
             throws ExecutionException {
-        return nodesCache.get(new StringValue(key), valueLoader);
+        if (isLeafPreviousDocId(key)) {
+            return prevDocumentsCache.get(new StringValue(key), valueLoader);
+        } else {
+            return nodeDocumentsCache.get(new StringValue(key), valueLoader);
+        }
     }
 
     /**
@@ -243,7 +271,6 @@ public class NodeDocumentCache implement
             throw new IllegalArgumentException("doc must not be NULL 
document");
         }
         String key = oldDoc.getId();
-
         Lock lock = locks.acquire(key);
         try {
             NodeDocument cached = getIfPresent(key);
@@ -265,21 +292,30 @@ public class NodeDocumentCache implement
     }
 
     /**
-     * Returns a view of the entries stored in this cache as a thread-safe map.
-     * Modifications made to the map directly affect the cache.
+     * @return keys stored in cache
+     */
+    public Iterable<CacheValue> keys() {
+        return Iterables.concat(nodeDocumentsCache.asMap().keySet(), 
prevDocumentsCache.asMap().keySet());
+    }
+
+    /**
+     * @return values stored in cache
      */
-    public Map<CacheValue, NodeDocument> asMap() {
-        return nodesCache.asMap();
+    public Iterable<NodeDocument> values() {
+        return Iterables.concat(nodeDocumentsCache.asMap().values(), 
prevDocumentsCache.asMap().values());
     }
 
-    public CacheStats getCacheStats() {
-        return cacheStats;
+    public Iterable<CacheStats> getCacheStats() {
+        return Lists.newArrayList(nodeDocumentsCacheStats, 
prevDocumentsCacheStats);
     }
 
     @Override
     public void close() throws IOException {
-        if (nodesCache instanceof Closeable) {
-            ((Closeable) nodesCache).close();
+        if (prevDocumentsCache instanceof Closeable) {
+            ((Closeable) prevDocumentsCache).close();
+        }
+        if (nodeDocumentsCache instanceof Closeable) {
+            ((Closeable) nodeDocumentsCache).close();
         }
     }
 
@@ -291,6 +327,10 @@ public class NodeDocumentCache implement
      * @param doc the document to put into the cache.
      */
     protected final void putInternal(@Nonnull NodeDocument doc) {
-        nodesCache.put(new StringValue(doc.getId()), doc);
+        if (isLeafPreviousDocId(doc.getId())) {
+            prevDocumentsCache.put(new StringValue(doc.getId()), doc);
+        } else {
+            nodeDocumentsCache.put(new StringValue(doc.getId()), doc);
+        }
     }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
 Fri Jan 29 02:53:12 2016
@@ -423,7 +423,7 @@ public class MemoryDocumentStore impleme
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         return null;
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 Fri Jan 29 02:53:12 2016
@@ -285,7 +285,7 @@ public class MongoDocumentStore implemen
     @Override
     public CacheInvalidationStats invalidateCache() {
         InvalidationResult result = new InvalidationResult();
-        for (CacheValue key : nodesCache.asMap().keySet()) {
+        for (CacheValue key : nodesCache.keys()) {
             result.invalidationCount++;
             invalidateCache(Collection.NODES, key.toString());
         }
@@ -1346,7 +1346,7 @@ public class MongoDocumentStore implemen
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         return nodesCache.getCacheStats();
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
 Fri Jan 29 02:53:12 2016
@@ -157,6 +157,32 @@ public enum CacheType {
         }
     },
 
+    PREV_DOCUMENT {
+        @Override
+        public <K> String keyToString(K key) {
+            return ((StringValue) key).asString();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public <K> K keyFromString(String key) {
+            return (K) StringValue.fromString(key);
+        }
+        @Override
+        public <K> int compareKeys(K a, K b) {
+            return ((StringValue) a).asString().compareTo(((StringValue) 
b).asString());
+        }
+        @Override
+        public <V> String valueToString(V value) {
+            return ((NodeDocument) value).asString();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public <V> V valueFromString(
+                DocumentNodeStore store, DocumentStore docStore, String value) 
{
+            return (V) NodeDocument.fromString(docStore, value);
+        }
+    },
+
     LOCAL_DIFF {
         @Override
         public <K> String keyToString(K key) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
 Fri Jan 29 02:53:12 2016
@@ -60,6 +60,7 @@ public class PersistentCache implements
     private boolean cacheChildren = true;
     private boolean cacheDiff = true;
     private boolean cacheLocalDiff = true;
+    private boolean cachePrevDocs = true;
     private boolean cacheDocs;
     private boolean cacheDocChildren;
     private boolean compactOnClose;
@@ -100,6 +101,8 @@ public class PersistentCache implements
         for (String p : parts) {
             if (p.equals("+docs")) {
                 cacheDocs = true;
+            } else if (p.equals("-prevDocs")) {
+                cachePrevDocs = false;
             } else if (p.equals("+docChildren")) {
                 cacheDocChildren = true;
             } else if (p.equals("-nodes")) {
@@ -383,7 +386,10 @@ public class PersistentCache implements
         case DOCUMENT:
             wrap = cacheDocs;
             break;
-        default:  
+        case PREV_DOCUMENT:
+            wrap = cachePrevDocs;
+            break;
+        default:
             wrap = false;
             break;
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
 Fri Jan 29 02:53:12 2016
@@ -486,7 +486,7 @@ public class RDBDocumentStore implements
 
     @Override
     public CacheInvalidationStats invalidateCache() {
-        for (NodeDocument nd : nodesCache.asMap().values()) {
+        for (NodeDocument nd : nodesCache.values()) {
             nd.markUpToDate(0);
         }
         return null;
@@ -658,7 +658,7 @@ public class RDBDocumentStore implements
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         return nodesCache.getCacheStats();
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
 Fri Jan 29 02:53:12 2016
@@ -186,7 +186,7 @@ public final class LeaseCheckDocumentSto
     }
 
     @Override
-    public final CacheStats getCacheStats() {
+    public final Iterable<CacheStats> getCacheStats() {
         performLeaseCheck();
         return delegate.getCacheStats();
     }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
 Fri Jan 29 02:53:12 2016
@@ -331,12 +331,12 @@ public class LoggingDocumentStoreWrapper
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         try {
             logMethod("getCacheStats");
-            return logResult(new Callable<CacheStats>() {
+            return logResult(new Callable<Iterable<CacheStats>>() {
                 @Override
-                public CacheStats call() throws Exception {
+                public Iterable<CacheStats> call() throws Exception {
                     return store.getCacheStats();
                 }
             });

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
 Fri Jan 29 02:53:12 2016
@@ -137,7 +137,7 @@ public class SynchronizingDocumentStoreW
     }
 
     @Override
-    public synchronized CacheStats getCacheStats() {
+    public synchronized Iterable<CacheStats> getCacheStats() {
         return store.getCacheStats();
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
 Fri Jan 29 02:53:12 2016
@@ -362,10 +362,10 @@ public class TimingDocumentStoreWrapper
 
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         try {
             long start = now();
-            CacheStats result = base.getCacheStats();
+            Iterable<CacheStats> result = base.getCacheStats();
             updateAndLogTimes("getCacheStats", start, 0, 0);
             return result;
         } catch (Exception e) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
 Fri Jan 29 02:53:12 2016
@@ -353,6 +353,16 @@ public class Utils {
     }
 
     /**
+     * Determines if the passed id belongs to a leaf level previous doc
+     *
+     * @param id id to check
+     * @return true if the id belongs to a leaf level previous doc
+     */
+    public static boolean isLeafPreviousDocId(String id){
+        return isPreviousDocId(id) && id.endsWith("/0");
+    }
+
+    /**
      * Deep copy of a map that may contain map values.
      *
      * @param source the source map

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/resources/OSGI-INF/metatype/metatype.properties
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/resources/OSGI-INF/metatype/metatype.properties
 Fri Jan 29 02:53:12 2016
@@ -45,6 +45,9 @@ mongouri.description = Represents a URI
 nodeCachePercentage.name = Percentage of cache reserved for nodeCache.
 nodeCachePercentage.description = Percentage of cache reserved for nodeCache.
 
+prevDocCachePercentage.name = Percentage of cache to be allocated towards 
Previous Document cache.
+prevDocCachePercentage.description = Percentage of cache to be allocated 
towards Previous Document cache.
+
 childrenCachePercentage.name = Percentage of cache reserved for childrenCache.
 childrenCachePercentage.description = Percentage of cache reserved for 
childrenCache.
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractMongoConnectionTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractMongoConnectionTest.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractMongoConnectionTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractMongoConnectionTest.java
 Fri Jan 29 02:53:12 2016
@@ -53,7 +53,11 @@ public abstract class AbstractMongoConne
     }
 
     protected DocumentMK.Builder newBuilder(DB db) throws Exception {
-        return new DocumentMK.Builder().clock(getTestClock()).setMongoDB(db);
+        return addToBuilder(new 
DocumentMK.Builder()).clock(getTestClock()).setMongoDB(db);
+    }
+
+    protected DocumentMK.Builder addToBuilder(DocumentMK.Builder mk) {
+        return mk;
     }
 
     protected Clock getTestClock() throws InterruptedException {

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
 Fri Jan 29 02:53:12 2016
@@ -217,7 +217,7 @@ public class CountingDocumentStore imple
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         return delegate.getCacheStats();
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
 Fri Jan 29 02:53:12 2016
@@ -151,7 +151,7 @@ public class DocumentStoreWrapper implem
     }
 
     @Override
-    public CacheStats getCacheStats() {
+    public Iterable<CacheStats> getCacheStats() {
         return store.getCacheStats();
     }
 

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java?rev=1727470&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java
 Fri Jan 29 02:53:12 2016
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import com.google.common.collect.Iterators;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.cache.CacheStats;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+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.spi.state.NodeStore;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+public class PreviousDocCacheTest extends AbstractMongoConnectionTest {
+
+    @Test
+    public void cacheTestPrevDocs() throws Exception {
+        DocumentNodeStore ns = mk.getNodeStore();
+        DocumentStore docStore = ns.getDocumentStore();
+
+        final int SPLIT_THRESHOLD = 10;
+        NodeBuilder b;
+
+        //Set property 110 times. Split at each 10. This should lead to 11 
leaf prev docs and 1 intermediate prev doc.
+        for (int j = 0; j <= SPLIT_THRESHOLD; j++) {
+            for (int i = 0; i < SPLIT_THRESHOLD; i++) {
+                b = ns.getRoot().builder();
+                b.setProperty("foo", "node-" + j + "-" + i);
+                merge(ns, b);
+            }
+            splitDocs(ns, SPLIT_THRESHOLD);
+        }
+
+        CacheStats nodesCache = null;
+        CacheStats prevDocsCache = null;
+        for (CacheStats cacheStats : docStore.getCacheStats()) {
+            if ("Document-Documents".equals(cacheStats.getName())) {
+                nodesCache = cacheStats;
+            } else if ("Document-PrevDocuments".equals(cacheStats.getName())) {
+                prevDocsCache = cacheStats;
+            }
+        }
+        assertNotNull("Nodes cache must not be null", nodesCache);
+        assertNotNull("Prev docs cache must not be null", prevDocsCache);
+
+        validateFullyLoadedCache(docStore, SPLIT_THRESHOLD, nodesCache, 
prevDocsCache);
+
+        docStore.invalidateCache();
+        assertEquals("No entries expected in nodes cache", 0, 
nodesCache.getElementCount());
+        assertEquals("No entries expected in prev docs cache", 0, 
prevDocsCache.getElementCount());
+
+        NodeDocument doc = docStore.find(NODES, "0:/");
+        assertEquals("Only main doc entry expected in nodes cache", 1, 
nodesCache.getElementCount());
+        assertEquals("No entries expected in prev docs cache", 0, 
prevDocsCache.getElementCount());
+
+        Iterators.size(doc.getAllPreviousDocs());
+        validateFullyLoadedCache(docStore, SPLIT_THRESHOLD, nodesCache, 
prevDocsCache);
+    }
+
+    private void validateFullyLoadedCache(DocumentStore docStore, int 
splitThreshold, CacheStats nodesCache, CacheStats prevDocsCache) {
+        assertEquals("Nodes cache must have 2 elements - '/' and intermediate 
split doc",
+                2, nodesCache.getElementCount());
+        assertEquals("Unexpected number of leaf prev docs", splitThreshold + 
1, prevDocsCache.getElementCount());
+
+        resetStats(nodesCache, prevDocsCache);
+        NodeDocument doc = docStore.getIfCached(NODES, "0:/");
+        assertEquals("Root doc must be available in nodes cache", 1, 
nodesCache.getHitCount());
+        assertEquals("Prev docs must not be read", 0, 
prevDocsCache.getHitCount());
+
+        Iterators.size(doc.getAllPreviousDocs());
+        assertEquals("Nodes cache should not have a miss", 0, 
nodesCache.getMissCount());
+        assertEquals("Prev docs cache should not have a miss", 0, 
prevDocsCache.getMissCount());
+    }
+
+    private void resetStats(CacheStats ... cacheStatses) {
+        for (CacheStats cacheStats : cacheStatses) {
+            cacheStats.resetStats();
+        }
+    }
+
+    private void splitDocs(DocumentNodeStore ns, int splitDocLimit) {
+        DocumentStore store = ns.getDocumentStore();
+        NodeDocument doc = Utils.getRootDocument(store);
+        List<UpdateOp> ops = SplitOperations.forDocument(doc,
+                ns, ns.getHeadRevision(), splitDocLimit/2);
+        assertFalse(ops.isEmpty());
+        for (UpdateOp op : ops) {
+            if (!op.isNew() ||
+                    !store.create(NODES, Collections.singletonList(op))) {
+                store.createOrUpdate(NODES, op);
+            }
+        }
+    }
+
+    private static void merge(NodeStore store, NodeBuilder builder)
+            throws CommitFailedException {
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PreviousDocCacheTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/CacheInvalidationIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/CacheInvalidationIT.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/CacheInvalidationIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/CacheInvalidationIT.java
 Fri Jan 29 02:53:12 2016
@@ -36,6 +36,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import static com.google.common.collect.Iterables.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -100,7 +101,7 @@ public class CacheInvalidationIT extends
         //Only 2 entries /a and /a/d would be invalidated
         // '/' would have been added to cache in start of backgroundRead
         //itself
-        assertEquals(initialCacheSizeC1 + totalPaths - 2, 
ds(c1).getNodeDocumentCache().asMap().size());
+        assertEquals(initialCacheSizeC1 + totalPaths - 2, 
size(ds(c1).getNodeDocumentCache().keys()));
     }
 
     @Test
@@ -141,7 +142,7 @@ public class CacheInvalidationIT extends
     }
 
     private int getCurrentCacheSize(DocumentNodeStore ds){
-        return ds(ds).getNodeDocumentCache().asMap().size();
+        return size(ds(ds).getNodeDocumentCache().keys());
     }
 
     private static void refreshHead(DocumentNodeStore store) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/JournalIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/JournalIT.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/JournalIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/JournalIT.java
 Fri Jan 29 02:53:12 2016
@@ -42,6 +42,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 public class JournalIT extends AbstractJournalTest {
 
@@ -66,7 +67,7 @@ public class JournalIT extends AbstractJ
     public void cacheInvalidationTest() throws Exception {
         final DocumentNodeStore ns1 = createMK(1, 0).getNodeStore();
         final DocumentNodeStore ns2 = createMK(2, 0).getNodeStore();
-        LOG.info("cache size 1: 
"+(ns1.getDocumentStore().getCacheStats()==null ? "null" : 
ns1.getDocumentStore().getCacheStats().getElementCount()));
+        LOG.info("cache size 1: " + 
getCacheElementCount(ns1.getDocumentStore()));
 
         // invalidate both caches under test first
         invalidateDocChildrenCache(ns1);
@@ -74,10 +75,9 @@ public class JournalIT extends AbstractJ
 
         {
             DocumentStore s = ns1.getDocumentStore();
-            CacheStats cacheStats = s.getCacheStats();
-            LOG.info("m.size="+(cacheStats==null ? "null" : 
cacheStats.getElementCount()));
+            LOG.info("m.size=" + getCacheElementCount(s));
         }
-        LOG.info("cache size 2: 
"+(ns1.getDocumentStore().getCacheStats()==null ? "null" : 
ns1.getDocumentStore().getCacheStats().getElementCount()));
+        LOG.info("cache size 2: " + 
getCacheElementCount(ns1.getDocumentStore()));
 
         // first create child node in instance 1
         final List<String> paths = createRandomPaths(1, 5000000, 1000);
@@ -97,11 +97,10 @@ public class JournalIT extends AbstractJ
 
         {
             DocumentStore s = ns1.getDocumentStore();
-            CacheStats cacheStats = s.getCacheStats();
-            LOG.info("m.size="+(cacheStats==null ? "null" : 
cacheStats.getElementCount()));
+            LOG.info("m.size=" + getCacheElementCount(s));
         }
 
-        LOG.info("cache size 2: 
"+(ns1.getDocumentStore().getCacheStats()==null ? "null" : 
ns1.getDocumentStore().getCacheStats().getElementCount()));
+        LOG.info("cache size 2: " + 
getCacheElementCount(ns1.getDocumentStore()));
         long time = System.currentTimeMillis();
         for(int j=0; j<100; j++) {
             long now = System.currentTimeMillis();
@@ -221,4 +220,17 @@ public class JournalIT extends AbstractJ
                 .setClusterId(clusterId).setAsyncDelay(asyncDelay).open());
     }
 
+    private static long getCacheElementCount(DocumentStore ds) {
+        if (ds.getCacheStats() == null) {
+            return -1;
+        }
+
+        long count = 0;
+        for (CacheStats cacheStats : ds.getCacheStats()) {
+            count += cacheStats.getElementCount();
+        }
+
+        return count;
+    }
+
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
 Fri Jan 29 02:53:12 2016
@@ -67,6 +67,18 @@ public class UtilsTest {
     }
 
     @Test
+    public void leafPreviousDoc() throws Exception {
+        Revision r = new Revision(System.currentTimeMillis(), 0, 0);
+        assertTrue(Utils.isLeafPreviousDocId(Utils.getPreviousIdFor("/", r, 
0)));
+        
assertTrue(Utils.isLeafPreviousDocId(Utils.getPreviousIdFor("/a/b/c/d/e/f/g/h/i/j/k/l/m",
 r, 0)));
+        
assertFalse(Utils.isLeafPreviousDocId(Utils.getPreviousIdFor("/a/b/c/d/e/f/g/h/i/j/k/l/m",
 r, 3)));
+        assertFalse(Utils.isLeafPreviousDocId(Utils.getIdFromPath("/a/b")));
+        assertFalse(Utils.isLeafPreviousDocId("foo"));
+        assertFalse(Utils.isLeafPreviousDocId("0:"));
+        assertFalse(Utils.isLeafPreviousDocId(":/0"));
+    }
+
+    @Test
     public void getParentIdFromLowerLimit() throws Exception{
         
assertEquals("1:/foo",Utils.getParentIdFromLowerLimit(Utils.getKeyLowerLimit("/foo")));
         assertEquals("1:/foo",Utils.getParentIdFromLowerLimit("2:/foo/bar"));

Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/nodestore/documentmk.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/nodestore/documentmk.md?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/nodestore/documentmk.md 
(original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/nodestore/documentmk.md Fri 
Jan 29 02:53:12 2016
@@ -467,20 +467,32 @@ can be backed by [persistent cache](pers
 1. `documentCache` - Document cache is used for caching the `NodeDocument` 
     instance. These are in memory representation of the persistent state. For 
     example in case of Mongo it maps to the Mongo document in `nodes` 
collection 
-    and for RDB its maps to the row in `NODES` table. 
+    and for RDB its maps to the row in `NODES` table. There is a class of 
`NodeDocument`
+    (leaf level split documents) which, since `1.3.15` are cached under
+    `prevDocCache` (see below)
     
     Depending on the `DocumentStore` implementation different heuristics are 
     applied for invalidating the cache entries based on changes in backend  
     
-2. `docChildrenCache` - Document Children cache is used to cache the children 
+2. `prevDocCache` - Previous document cache is used for caching the 
`NodeDocument` 
+    instance representing leaf level split documents. Unlike other type of
+    `NodeDocument`, these are immutable and hence don't require invalidation.
+    If configured, this cache can exploit persistent cache as well.
+    Similar to other `NodeDocument` these are also in memory representation of
+    the persistent state. (since `1.3.15`)
+    
+    Depending on the `DocumentStore` implementation different heuristics are 
+    applied for invalidating the cache entries based on changes in backend  
+    
+3. `docChildrenCache` - Document Children cache is used to cache the children 
     state for a given parent node. This is invalidated completely upon every 
     background read
     
-3. `nodeCache` - Node cache is used to cache the `DocumentNodeState` instances.
+4. `nodeCache` - Node cache is used to cache the `DocumentNodeState` instances.
     These are **immutable** view of `NodeDocument` as seen at a given revision
     hence no consistency checks are to be performed for them
      
-4. `childrenCache` - Children cache is used to cache the children for a given
+5. `childrenCache` - Children cache is used to cache the children for a given
     node. These are also **immutable** and represent the state of children for
     a given parent at certain revision
     
@@ -528,10 +540,11 @@ takes a single config for `cache` which
 various caches above in following way
 
 1. `nodeCache` - 25%
-2. `childrenCache` - 10% 
-3. `docChildrenCache` - 3% 
-4. `diffCache` - 5% 
-5. `documentCache` - Is given the rest i.e. 57%
+2. `prevDocCache` - 4% 
+3. `childrenCache` - 10% 
+4. `docChildrenCache` - 3% 
+5. `diffCache` - 5% 
+6. `documentCache` - Is given the rest i.e. 57%
 
 Lately [options are provided][OAK-2546] to have a fine grained control over 
the 
 distribution. See [Cache Allocation][cache-allocation]

Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/osgi_config.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/osgi_config.md?rev=1727470&r1=1727469&r2=1727470&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/osgi_config.md (original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/osgi_config.md Fri Jan 29 
02:53:12 2016
@@ -109,6 +109,11 @@ nodeCachePercentage
 : Default 25
 : Percentage of `cache` allocated for `nodeCache`. See [Caching][doc-cache]
 
+prevDocCachePercentage
+: Default 4
+: Percentage of `cache` allocated for `prevDocCache`. See [Caching][doc-cache]
+: Since 1.3.15
+
 childrenCachePercentage
 : Default 10
 : Percentage of `cache` allocated for `childrenCache`. See [Caching][doc-cache]


Reply via email to