jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r1365510 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak: kernel/KernelNodeStateBuilder.java kernel/KernelRootStateBuilder.java plugins/memory/MemoryNodeStateBuilder.java
Date Wed, 25 Jul 2012 09:58:15 GMT
Author: jukka
Date: Wed Jul 25 09:58:15 2012
New Revision: 1365510

URL: http://svn.apache.org/viewvc?rev=1365510&view=rev
Log:
OAK-167: Caching NodeStore implementation

Allow unmodified MNSB instances to be garbage-collected by reversing the parent-child references
until something is actually modified.

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootStateBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStateBuilder.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java?rev=1365510&r1=1365509&r2=1365510&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
Wed Jul 25 09:58:15 2012
@@ -23,14 +23,17 @@ class KernelNodeStateBuilder extends Mem
 
     private final KernelRootStateBuilder root;
 
-    public KernelNodeStateBuilder(NodeState base, KernelRootStateBuilder root) {
-        super(base);
+    public KernelNodeStateBuilder(
+            MemoryNodeStateBuilder parent, String name,
+            NodeState base, KernelRootStateBuilder root) {
+        super(parent, name, base);
         this.root = root;
     }
 
     @Override
-    protected MemoryNodeStateBuilder createChildBuilder(NodeState child) {
-        return new KernelNodeStateBuilder(child, root);
+    protected MemoryNodeStateBuilder createChildBuilder(
+            String name, NodeState child) {
+        return new KernelNodeStateBuilder(this, name, child, root);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootStateBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootStateBuilder.java?rev=1365510&r1=1365509&r2=1365510&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootStateBuilder.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootStateBuilder.java
Wed Jul 25 09:58:15 2012
@@ -28,8 +28,9 @@ class KernelRootStateBuilder extends Mem
     }
 
     @Override
-    protected MemoryNodeStateBuilder createChildBuilder(NodeState child) {
-        return new KernelNodeStateBuilder(child, this);
+    protected MemoryNodeStateBuilder createChildBuilder(
+            String name, NodeState child) {
+        return new KernelNodeStateBuilder(this, name, child, this);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStateBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStateBuilder.java?rev=1365510&r1=1365509&r2=1365510&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStateBuilder.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStateBuilder.java
Wed Jul 25 09:58:15 2012
@@ -16,60 +16,128 @@
  */
 package org.apache.jackrabbit.oak.plugins.memory;
 
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateBuilder;
+
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
-import org.apache.jackrabbit.oak.api.CoreValue;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateBuilder;
 
 /**
- * Basic in-memory node state builder.
+ * In-memory node state builder. 
  */
 public class MemoryNodeStateBuilder implements NodeStateBuilder {
 
-    private final NodeState base;
+    private static final NodeState NULL_STATE = new MemoryNodeState(
+            ImmutableMap.<String, PropertyState>of(),
+            ImmutableMap.<String, NodeState>of());
+
+    /**
+     * Parent state builder reference, or {@code null} for a connected
+     * builder.
+     */
+    private MemoryNodeStateBuilder parent;
+
+    /**
+     * Name of this child node within the parent builder, or {@code null}
+     * for a connected builder.
+     */
+    private String name;
+
+    // TODO: (Atomic)Reference for use with connect?
+    private NodeState base;
 
     /**
      * Set of added, modified or removed ({@code null} value) property states.
      */
-    private Map<String, PropertyState> properties = Maps.newHashMap();
+    private Map<String, PropertyState> properties;
 
     /**
      * Set of builders for added, modified or removed ({@code null} value)
      * child nodes.
      */
-    private final Map<String, NodeStateBuilder> builders = Maps.newHashMap();
+    private Map<String, MemoryNodeStateBuilder> builders;
 
     /**
-     * Flag to indicate that the current {@link #properties} map is being
-     * referenced by a {@link ModifiedNodeState} instance returned by a
-     * previous {@link #getNodeState()} call, and thus should not be
-     * modified unless first explicitly {@link #unfreeze() unfrozen}.
+     * Creates a new in-memory node state builder.
+     *
+     * @param parent parent node state builder
+     * @param name name of this node
+     * @param base base state of this node
      */
-    private boolean frozen;
+    protected MemoryNodeStateBuilder(
+            MemoryNodeStateBuilder parent, String name, NodeState base) {
+        this.parent = parent;
+        this.name = name;
+        this.properties = ImmutableMap.of();
+        this.builders = ImmutableMap.of();
+        this.base = base;
+    }
 
     /**
      * Creates a new in-memory node state builder.
      *
-     * @param base base state of the new builder, or {@code null}
+     * @param base base state of the new builder
      */
     public MemoryNodeStateBuilder(NodeState base) {
-        if (base != null) {
-            this.base = base;
-        } else {
-            this.base = MemoryNodeState.EMPTY_NODE;
+        this.parent = null;
+        this.name = null;
+        this.properties = Maps.newHashMap();
+        this.builders = Maps.newHashMap();
+        this.base = base;
+    }
+
+    private void connect(boolean modify) {
+        if (parent != null) {
+            parent.connect(modify);
+
+            MemoryNodeStateBuilder existing = parent.builders.get(name);
+            if (existing != null) {
+                properties = existing.properties;
+                builders = existing.builders;
+                parent = null;
+                name = null;
+            } else if (modify) {
+                parent.builders.put(name, this);
+                properties = Maps.newHashMap();
+                builders = Maps.newHashMap();
+                parent = null;
+                name = null;
+            }
+        }
+    }
+
+    private void reset(NodeState newBase) {
+        base = newBase;
+
+        properties.clear();
+
+        Iterator<Map.Entry<String, MemoryNodeStateBuilder>> iterator =
+                builders.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, MemoryNodeStateBuilder> entry = iterator.next();
+            MemoryNodeStateBuilder childBuilder = entry.getValue();
+            NodeState childBase = base.getChildNode(entry.getKey());
+            if (childBase == null || childBuilder == null) {
+                iterator.remove();
+            } else {
+                childBuilder.reset(childBase);
+            }
         }
     }
 
@@ -80,8 +148,9 @@ public class MemoryNodeStateBuilder impl
      * @param child base state of the new builder, or {@code null}
      * @return new builder
      */
-    protected MemoryNodeStateBuilder createChildBuilder(NodeState child) {
-        return new MemoryNodeStateBuilder(child);
+    protected MemoryNodeStateBuilder createChildBuilder(
+            String name, NodeState child) {
+        return new MemoryNodeStateBuilder(this, name, child);
     }
 
     /**
@@ -95,74 +164,66 @@ public class MemoryNodeStateBuilder impl
         // do nothing
     }
 
-    /**
-     * Ensures that the current {@link #properties} map is not {@link #frozen}.
-     */
-    private void unfreeze() {
-        if (frozen) {
-            properties = new HashMap<String, PropertyState>(properties);
-            frozen = false;
-        }
-    }
-
     @Override
     public NodeState getNodeState() {
-        Map<String, PropertyState> props = Collections.emptyMap();
-        if (!properties.isEmpty()) {
-            frozen = true;
-            props = properties;
-        }
-
-        Map<String, NodeState> nodes = Collections.emptyMap();
-        if (!builders.isEmpty()) {
-            nodes = new HashMap<String, NodeState>(builders.size() * 2);
-            for (Map.Entry<String, NodeStateBuilder> entry
-                    : builders.entrySet()) {
-                NodeStateBuilder builder = entry.getValue();
-                if (builder != null) {
-                    nodes.put(entry.getKey(), builder.getNodeState());
-                } else {
-                    nodes.put(entry.getKey(), null);
-                }
-            }
+        connect(false);
+
+        if (parent != null) {
+            return base; // shortcut
         }
 
-        if (props.isEmpty() && nodes.isEmpty()) {
-            return base;
-        } else {
-            return new ModifiedNodeState(base, props, nodes);
+        Map<String, PropertyState> props = Maps.newHashMap(properties);
+        Map<String, NodeState> nodes = Maps.newHashMap();
+        for (Map.Entry<String, MemoryNodeStateBuilder> entry
+                : builders.entrySet()) {
+            NodeStateBuilder builder = entry.getValue();
+            if (builder != null) {
+                nodes.put(entry.getKey(), builder.getNodeState());
+            } else {
+                nodes.put(entry.getKey(), null);
+            }
         }
+
+        return new ModifiedNodeState(base, props, nodes);
     }
 
     @Override
     public long getChildNodeCount() {
+        connect(false);
+
         long count = base.getChildNodeCount();
-        for (Map.Entry<String, NodeStateBuilder> entry : builders.entrySet()) {
-            NodeState before = base.getChildNode(entry.getKey());
-            NodeStateBuilder after = entry.getValue();
-            if (before == null && after != null) {
-                count++;
-            } else if (before != null && after == null) {
+
+        for (Map.Entry<String, MemoryNodeStateBuilder> entry
+                : builders.entrySet()) {
+            if (base.getChildNode(entry.getKey()) != null) {
                 count--;
             }
+            if (entry.getValue() != null) {
+                count++;
+            }
         }
+
         return count;
     }
 
     @Override
     public boolean hasChildNode(String name) {
+        connect(false);
+
         NodeStateBuilder builder = builders.get(name);
         if (builder != null) {
             return true;
         } else if (builders.containsKey(name)) {
             return false;
-        } else {
-            return base.getChildNode(name) != null;
         }
+
+        return base.getChildNode(name) != null;
     }
 
     @Override
     public Iterable<String> getChildNodeNames() {
+        connect(false);
+
         Iterable<String> unmodified = Iterables.transform(
                 base.getChildNodeEntries(),
                 new Function<ChildNodeEntry, String>() {
@@ -171,6 +232,10 @@ public class MemoryNodeStateBuilder impl
                         return input.getName();
                     }
                 });
+        if (parent != null) {
+            return unmodified; // shortcut
+        }
+
         Predicate<String> unmodifiedFilter = Predicates.not(Predicates.in(
                 ImmutableSet.copyOf(builders.keySet())));
         Set<String> modified = ImmutableSet.copyOf(
@@ -181,107 +246,136 @@ public class MemoryNodeStateBuilder impl
     }
 
     @Override
-    public void setNode(String name, NodeState nodeState) {
-        if (nodeState == null) {
-            removeNode(name);
+    public void setNode(String name, NodeState state) {
+        connect(true);
+
+        MemoryNodeStateBuilder builder = builders.get(name);
+        if (builder != null) {
+            builder.reset(state);
         } else {
-            if (nodeState.equals(base.getChildNode(name))) {
-                builders.remove(name);
-            } else {
-                builders.put(name, createChildBuilder(nodeState));
-            }
-            updated();
+            createChildBuilder(name, state).connect(true);
         }
+
+        updated();
     }
 
     @Override
     public void removeNode(String name) {
+        connect(true);
+
         if (base.getChildNode(name) != null) {
             builders.put(name, null);
         } else {
             builders.remove(name);
         }
+
         updated();
     }
 
     @Override
     public long getPropertyCount() {
+        connect(false);
+
         long count = base.getPropertyCount();
+
         for (Map.Entry<String, PropertyState> entry : properties.entrySet()) {
-            PropertyState before = base.getProperty(entry.getKey());
-            PropertyState after = entry.getValue();
-            if (before == null && after != null) {
-                count++;
-            } else if (before != null && after == null) {
+            if (base.getProperty(entry.getKey()) != null) {
                 count--;
             }
+            if (entry.getValue() != null) {
+                count++;
+            }
         }
+
         return count;
     }
 
     @Override
     public Iterable<? extends PropertyState> getProperties() {
-        frozen = true;
-        final Set<String> names = properties.keySet();
-        Predicate<PropertyState> predicate = new Predicate<PropertyState>() {
+        connect(false);
+
+        Iterable<? extends PropertyState> unmodified = base.getProperties();
+        if (parent != null) {
+            return unmodified; // shortcut
+        }
+
+        final Set<String> names = ImmutableSet.copyOf(properties.keySet());
+        Predicate<PropertyState> filter = new Predicate<PropertyState>() {
             @Override
             public boolean apply(PropertyState input) {
                 return !names.contains(input.getName());
             }
         };
+        Collection<PropertyState> modified = ImmutableList.copyOf(
+                Collections2.filter(properties.values(), Predicates.notNull()));
         return Iterables.concat(
-                Iterables.filter(properties.values(), Predicates.notNull()),
-                Iterables.filter(base.getProperties(), predicate));
+                Iterables.filter(unmodified, filter),
+                modified);
     }
 
 
     @Override
     public PropertyState getProperty(String name) {
+        connect(false);
+
         PropertyState property = properties.get(name);
         if (property != null || properties.containsKey(name)) {
             return property;
-        } else {
-            return base.getProperty(name);
         }
+
+        return base.getProperty(name);
     }
 
     @Override
     public void setProperty(String name, CoreValue value) {
-        unfreeze();
+        connect(true);
+
         properties.put(name, new SinglePropertyState(name, value));
+
         updated();
     }
 
     @Override
     public void setProperty(String name, List<CoreValue> values) {
-        unfreeze();
+        connect(true);
+
         if (values.isEmpty()) {
             properties.put(name, new EmptyPropertyState(name));
         } else {
             properties.put(name, new MultiPropertyState(name, values));
         }
+
         updated();
     }
 
     @Override
     public void removeProperty(String name) {
-        unfreeze();
+        connect(true);
+
         if (base.getProperty(name) != null) {
             properties.put(name, null);
         } else {
             properties.remove(name);
         }
+
         updated();
     }
 
     @Override
     public NodeStateBuilder getChildBuilder(String name) {
-        NodeStateBuilder builder = builders.get(name);
+        connect(true);
+
+        MemoryNodeStateBuilder builder = builders.get(name);
         if (builder == null) {
             NodeState baseState = base.getChildNode(name);
-            builder = createChildBuilder(baseState);
+            if (baseState == null) {
+                baseState = NULL_STATE;
+            }
+            builder = createChildBuilder(name, baseState);
+            builder.connect(true);
             builders.put(name, builder);
         }
+
         return builder;
     }
 



Mime
View raw message