Index: trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java (revision 1665255) +++ trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java (revision ) @@ -30,6 +30,7 @@ import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.cache.DisableableCache; import org.apache.jackrabbit.oak.core.MutableRoot.Move; import org.apache.jackrabbit.oak.plugins.tree.impl.AbstractMutableTree; import org.apache.jackrabbit.oak.spi.state.NodeBuilder; @@ -122,16 +123,23 @@ return super.exists(); } + private DisableableCache propertyCache = new DisableableCache("MutableTree.propertyCache", false); + @Override public PropertyState getProperty(@Nonnull String name) { beforeRead(); - return super.getProperty(name); + PropertyState property = propertyCache.get(name); + if (property == null) { + property = super.getProperty(name); + propertyCache.set(name, property); - } + } + return property; + } @Override public boolean hasProperty(@Nonnull String name) { beforeRead(); - return super.hasProperty(name); + return propertyCache.has(name) || super.hasProperty(name); } @Override @@ -183,6 +191,8 @@ @Override public boolean remove() { beforeWrite(); + propertyCache.clear(); + treeCache.clear(); boolean success = super.remove(); if (success) { root.updated(); @@ -198,6 +208,7 @@ if (hasChild(name)) { child = createChild(name); } else { + treeCache.removeStartsWith(name); child = super.addChild(name); root.updated(); } @@ -230,6 +241,7 @@ @Override public void setProperty(@Nonnull String name, @Nonnull T value) { beforeWrite(); + propertyCache.remove(name); super.setProperty(name, value); root.updated(); } @@ -237,6 +249,7 @@ @Override public void setProperty(@Nonnull String name, @Nonnull T value, @Nonnull Type type) { beforeWrite(); + propertyCache.remove(name); super.setProperty(name, value, type); root.updated(); } @@ -244,6 +257,7 @@ @Override public void removeProperty(@Nonnull String name) { beforeWrite(); + propertyCache.remove(name); super.removeProperty(name); root.updated(); } @@ -276,6 +290,8 @@ return success; } + private DisableableCache treeCache = new DisableableCache("MutableTree.treeCache"); + /** * Get a possibly non existing tree. * @param path the path to the tree @@ -285,9 +301,14 @@ MutableTree getTree(@Nonnull String path) { checkArgument(isAbsolute(checkNotNull(path))); beforeRead(); - MutableTree child = this; + + MutableTree child = treeCache.get(path); + if (child == null) { + child = this; - for (String name : elements(path)) { - child = new MutableTree(root, pendingMoves, child, child.nodeBuilder.getChildNode(name), name); + for (String name : elements(path)) { + child = new MutableTree(root, pendingMoves, child, child.nodeBuilder.getChildNode(name), name); + } + treeCache.set(path, child); } return child; } Index: trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (revision 1665255) +++ trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (revision ) @@ -43,6 +43,7 @@ import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.cache.DisableableCache; import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.spi.state.EqualsDiff; import org.apache.jackrabbit.oak.spi.state.MoveDetector; @@ -239,6 +240,7 @@ checkState(parent == null); base = checkNotNull(newBase); baseRevision = rootHead.setState(newBase) + 1; + nodeBuilderCache.clear(); } /** @@ -254,6 +256,7 @@ } else { parent.setChildNode(name, newState); } + nodeBuilderCache.clear(); } //--------------------------------------------------------< NodeBuilder >--- @@ -322,10 +325,17 @@ } } + private DisableableCache nodeBuilderCache = new DisableableCache("MemoryNodeBuilder.nodeBuilderCache"); + @Override public NodeBuilder getChildNode(String name) { checkValidName(name); - return createChildBuilder(name); + NodeBuilder nodeBuilder = nodeBuilderCache.get(name); + if (nodeBuilder == null) { + nodeBuilder = createChildBuilder(name); + nodeBuilderCache.set(name, nodeBuilder); + } + return nodeBuilder; } @Override Index: trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/DisableableCache.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/DisableableCache.java (revision ) +++ trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/DisableableCache.java (revision ) @@ -0,0 +1,62 @@ +package org.apache.jackrabbit.oak.cache; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Created by joelrich on 08/04/15. + */ +public class DisableableCache { + + private final Map cache; + + public DisableableCache(String name) { + this(name, true); + } + + public DisableableCache(String name, boolean defaultEnabled) { + String property = System.getProperty(name); + boolean enabled = (defaultEnabled && !"false".equals(property)) || "true".equals(property); + cache = enabled ? new HashMap() : null; + } + + public boolean has(String key) { + return cache != null && key != null && cache.containsKey(key); + } + + public V get(String key) { + return (cache != null && key != null) ? cache.get(key) : null; + } + + public void remove(String key) { + if (cache != null && key != null) { + cache.remove(key); + } + } + + public void clear() { + if (cache != null) { + cache.clear(); + } + } + + public void set(String key, V value) { + if (cache != null && key != null && value != null) { + cache.put(key, value); + } + } + + public void removeStartsWith(String keyPrefix) { + if (cache != null && keyPrefix != null) { + Iterator keys = cache.keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + if (key.startsWith(keyPrefix)) { + keys.remove(); + } + } + } + } + +}