You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/07/26 10:56:50 UTC

svn commit: r1365916 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory: MemoryChildNodeEntry.java MemoryNodeStateBuilder.java ModifiedNodeState.java

Author: jukka
Date: Thu Jul 26 08:56:50 2012
New Revision: 1365916

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

Encapsulate the mutable/modified state handling inside MemoryNodeStateBuilder

Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryChildNodeEntry.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/plugins/memory/MemoryChildNodeEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryChildNodeEntry.java?rev=1365916&r1=1365915&r2=1365916&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryChildNodeEntry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryChildNodeEntry.java Thu Jul 26 08:56:50 2012
@@ -32,20 +32,22 @@ import com.google.common.collect.Iterabl
  * Basic JavaBean implementation of a child node entry.
  */
 public class MemoryChildNodeEntry extends AbstractChildNodeEntry {
-    private final String name;
-    private final NodeState node;
 
-    public static Iterable<ChildNodeEntry> iterable(
-            final Iterable<Entry<String, NodeState>> iterable) {
+    public static <T extends NodeState> Iterable<ChildNodeEntry> iterable(
+            Iterable<Entry<String, T>> set) {
         return Iterables.transform(
-                iterable,
-                new Function<Entry<String, NodeState>, ChildNodeEntry>() {
+                set,
+                new Function<Entry<String, T>, ChildNodeEntry>() {
                     @Override
-                    public ChildNodeEntry apply(Entry<String, NodeState> input) {
+                    public ChildNodeEntry apply(Entry<String, T> input) {
                         return new MemoryChildNodeEntry(input);
                     }
                 });
-    }
+   }
+
+    private final String name;
+
+    private final NodeState node;
 
     /**
      * Creates a child node entry with the given name and referenced
@@ -68,7 +70,7 @@ public class MemoryChildNodeEntry extend
      *
      * @param entry map entry
      */
-    public MemoryChildNodeEntry(Map.Entry<String, NodeState> entry) {
+    public MemoryChildNodeEntry(Map.Entry<String, ? extends NodeState> entry) {
         this(entry.getKey(), entry.getValue());
     }
 

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=1365916&r1=1365915&r2=1365916&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 Thu Jul 26 08:56:50 2012
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -30,6 +29,7 @@ import org.apache.jackrabbit.oak.spi.sta
 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 org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -38,6 +38,7 @@ import com.google.common.collect.Immutab
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 /**
@@ -206,7 +207,7 @@ public class MemoryNodeStateBuilder impl
     public NodeState getNodeState() {
         NodeState state = read();
         if (writeState != null) {
-            return writeState.snapshot();
+            return new ModifiedNodeState(writeState);
         } else {
             return state;
         }
@@ -275,7 +276,7 @@ public class MemoryNodeStateBuilder impl
     public void setProperty(String name, CoreValue value) {
         MutableNodeState mstate = write();
 
-        mstate.properties.put(name, new SinglePropertyState(name, value));
+        mstate.props.put(name, new SinglePropertyState(name, value));
 
         updated();
     }
@@ -285,9 +286,9 @@ public class MemoryNodeStateBuilder impl
         MutableNodeState mstate = write();
 
         if (values.isEmpty()) {
-            mstate.properties.put(name, new EmptyPropertyState(name));
+            mstate.props.put(name, new EmptyPropertyState(name));
         } else {
-            mstate.properties.put(name, new MultiPropertyState(name, values));
+            mstate.props.put(name, new MultiPropertyState(name, values));
         }
 
         updated();
@@ -298,9 +299,9 @@ public class MemoryNodeStateBuilder impl
         MutableNodeState mstate = write();
 
         if (mstate.base.getProperty(name) != null) {
-            mstate.properties.put(name, null);
+            mstate.props.put(name, null);
         } else {
-            mstate.properties.remove(name);
+            mstate.props.remove(name);
         }
 
         updated();
@@ -333,6 +334,42 @@ public class MemoryNodeStateBuilder impl
     }
 
     /**
+     * Filter for skipping property states with given names.
+     */
+    private static class SkipNamedProps implements Predicate<PropertyState> {
+
+        private final Set<String> names;
+
+        private SkipNamedProps(Set<String> names) {
+            this.names = names;
+        }
+
+        @Override
+        public boolean apply(PropertyState input) {
+            return !names.contains(input.getName());
+        }
+
+    }
+
+    /**
+     * Filter for skipping child node states with given names.
+     */
+    private static class SkipNamedNodes implements Predicate<ChildNodeEntry> {
+
+        private final Set<String> names;
+
+        private SkipNamedNodes(Set<String> names) {
+            this.names = names;
+        }
+
+        @Override
+        public boolean apply(ChildNodeEntry input) {
+            return !names.contains(input.getName());
+        }
+
+    }
+
+    /**
      * The <em>mutable</em> state being built. Instances of this class
      * are never passed beyond the containing MemoryNodeStateBuilder,
      * so it's not a problem that we intentionally break the immutability
@@ -343,44 +380,29 @@ public class MemoryNodeStateBuilder impl
         /**
          * The immutable base state.
          */
-        private NodeState base;
+        protected NodeState base;
 
         /**
          * Set of added, modified or removed ({@code null} value)
          * property states.
          */
-        private final Map<String, PropertyState> properties =
+        protected final Map<String, PropertyState> props =
                 Maps.newHashMap();
 
         /**
          * Set of added, modified or removed ({@code null} value)
          * child nodes.
          */
-        private final Map<String, MutableNodeState> nodes =
+        protected final Map<String, MutableNodeState> nodes =
                 Maps.newHashMap();
 
         public MutableNodeState(NodeState base) {
             this.base = checkNotNull(base);
         }
 
-        private NodeState snapshot() {
-            Map<String, PropertyState> props = Maps.newHashMap(properties);
-            Map<String, NodeState> snapshots = Maps.newHashMap();
-            for (Map.Entry<String, MutableNodeState> entry : nodes.entrySet()) {
-                String name = entry.getKey();
-                MutableNodeState node = entry.getValue();
-                if (node != null) {
-                    snapshots.put(name, node.snapshot());
-                } else {
-                    snapshots.put(name, null);
-                }
-            }
-            return new ModifiedNodeState(base, props, snapshots);
-        }
-
         private void reset(NodeState newBase) {
             base = newBase;
-            properties.clear();
+            props.clear();
 
             Iterator<Map.Entry<String, MutableNodeState>> iterator =
                     nodes.entrySet().iterator();
@@ -402,8 +424,7 @@ public class MemoryNodeStateBuilder impl
         public long getPropertyCount() {
             long count = base.getPropertyCount();
 
-            for (Map.Entry<String, PropertyState> entry
-                    : properties.entrySet()) {
+            for (Map.Entry<String, PropertyState> entry : props.entrySet()) {
                 if (base.getProperty(entry.getKey()) != null) {
                     count--;
                 }
@@ -417,8 +438,8 @@ public class MemoryNodeStateBuilder impl
 
         @Override
         public PropertyState getProperty(String name) {
-            PropertyState property = properties.get(name);
-            if (property != null || properties.containsKey(name)) {
+            PropertyState property = props.get(name);
+            if (property != null || props.containsKey(name)) {
                 return property;
             }
 
@@ -427,18 +448,21 @@ public class MemoryNodeStateBuilder impl
 
         @Override
         public Iterable<? extends PropertyState> getProperties() {
-            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 = Collections2.filter(
-                    properties.values(), Predicates.notNull());
+            if (props.isEmpty()) {
+                return base.getProperties(); // shortcut
+            } else {
+                return internalGetProperties();
+            }
+        }
+
+        protected Iterable<? extends PropertyState> internalGetProperties() {
+            Predicate<PropertyState> unmodifiedFilter =
+                    new SkipNamedProps(ImmutableSet.copyOf(props.keySet()));
+            Predicate<PropertyState> modifiedFilter = Predicates.notNull();
             return Iterables.concat(
-                    Iterables.filter(base.getProperties(), filter),
-                    ImmutableList.copyOf(modified));
+                    Iterables.filter(base.getProperties(), unmodifiedFilter),
+                    ImmutableList.copyOf(Collections2.filter(
+                            props.values(), modifiedFilter)));
         }
 
         @Override
@@ -471,6 +495,14 @@ public class MemoryNodeStateBuilder impl
 
         @Override
         public Iterable<String> getChildNodeNames() {
+            if (nodes.isEmpty()) {
+                return base.getChildNodeNames(); // shortcut
+            } else {
+                return internalGetChildNodeNames();
+            }
+        }
+
+        protected Iterable<String> internalGetChildNodeNames() {
             Iterable<String> unmodified = base.getChildNodeNames();
             Predicate<String> unmodifiedFilter = Predicates.not(Predicates.in(
                     ImmutableSet.copyOf(nodes.keySet())));
@@ -483,10 +515,171 @@ public class MemoryNodeStateBuilder impl
 
         @Override
         public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-            // TODO Auto-generated method stub
-            return null;
+            if (nodes.isEmpty()) {
+                return base.getChildNodeEntries(); // shortcut
+            } else {
+                return internalGetChildNodeEntries();
+            }
         }
 
+        protected Iterable<? extends ChildNodeEntry> internalGetChildNodeEntries() {
+            Iterable<? extends ChildNodeEntry> unmodified =
+                    base.getChildNodeEntries();
+            Predicate<ChildNodeEntry> unmodifiedFilter =
+                    new SkipNamedNodes(ImmutableSet.copyOf(nodes.keySet()));
+
+            List<ChildNodeEntry> modified = Lists.newArrayList();
+            for (Map.Entry<String, MutableNodeState> entry : nodes.entrySet()) {
+                MutableNodeState cstate = entry.getValue();
+                if (cstate != null) {
+                    modified.add(new MemoryChildNodeEntry(
+                            entry.getKey(),
+                            new ModifiedNodeState(cstate)));
+                }
+            }
+
+            return Iterables.concat(
+                    Iterables.filter(unmodified, unmodifiedFilter),
+                    modified);
+        }
+
+        /**
+         * Since we keep track of an explicit base node state for a
+         * {@link ModifiedNodeState} instance, we can do this in two steps:
+         * first compare the base states to each other (often a fast operation),
+         * ignoring all changed properties and child nodes for which we have
+         * further modifications, and then compare all the modified properties
+         * and child nodes to those in the given base state.
+         */
+        @Override
+        public void compareAgainstBaseState(
+                NodeState base, final NodeStateDiff diff) {
+            this.base.compareAgainstBaseState(base, new NodeStateDiff() {
+                @Override
+                public void propertyAdded(PropertyState after) {
+                    if (!props.containsKey(after.getName())) {
+                        diff.propertyAdded(after);
+                    }
+                }
+                @Override
+                public void propertyChanged(
+                        PropertyState before, PropertyState after) {
+                    if (!props.containsKey(before.getName())) {
+                        diff.propertyChanged(before, after);
+                    }
+                }
+                @Override
+                public void propertyDeleted(PropertyState before) {
+                    if (!props.containsKey(before.getName())) {
+                        diff.propertyDeleted(before);
+                    }
+                }
+                @Override
+                public void childNodeAdded(String name, NodeState after) {
+                    if (!nodes.containsKey(name)) {
+                        diff.childNodeAdded(name, after);
+                    }
+                }
+                @Override
+                public void childNodeChanged(String name, NodeState before, NodeState after) {
+                    if (!nodes.containsKey(name)) {
+                        diff.childNodeChanged(name, before, after);
+                    }
+                }
+                @Override
+                public void childNodeDeleted(String name, NodeState before) {
+                    if (!nodes.containsKey(name)) {
+                        diff.childNodeDeleted(name, before);
+                    }
+                }
+            });
+
+            for (Map.Entry<String, PropertyState> entry : props.entrySet()) {
+                PropertyState before = base.getProperty(entry.getKey());
+                PropertyState after = entry.getValue();
+                if (before == null && after == null) {
+                    // do nothing
+                } else if (after == null) {
+                    diff.propertyDeleted(before);
+                } else if (before == null) {
+                    diff.propertyAdded(after);
+                } else if (!before.equals(after)) {
+                    diff.propertyChanged(before, after);
+                }
+            }
+
+            for (Map.Entry<String, MutableNodeState> entry : nodes.entrySet()) {
+                String name = entry.getKey();
+                NodeState before = base.getChildNode(name);
+                NodeState after = entry.getValue();
+                if (before == null && after == null) {
+                    // do nothing
+                } else if (after == null) {
+                    diff.childNodeDeleted(name, before);
+                } else if (before == null) {
+                    diff.childNodeAdded(name, after);
+                } else if (!before.equals(after)) {
+                    diff.childNodeChanged(name, before, after);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Immutable snapshot of a mutable node state.
+     */
+    private static class ModifiedNodeState extends MutableNodeState {
+
+        public ModifiedNodeState(MutableNodeState mstate) {
+            super(mstate.base);
+            props.putAll(mstate.props);
+            for (Map.Entry<String, MutableNodeState> entry
+                    : mstate.nodes.entrySet()) {
+                String name = entry.getKey();
+                MutableNodeState node = entry.getValue();
+                if (node != null) {
+                    nodes.put(name, new ModifiedNodeState(node));
+                } else {
+                    nodes.put(name, null);
+                }
+            }
+        }
+
+        //----------------------------------------------< MutableNodeState >--
+
+        @Override
+        protected Iterable<? extends PropertyState> internalGetProperties() {
+            Predicate<PropertyState> unmodifiedFilter =
+                    new SkipNamedProps(props.keySet());
+            Predicate<PropertyState> modifiedFilter = Predicates.notNull();
+            return Iterables.concat(
+                    Iterables.filter(base.getProperties(), unmodifiedFilter),
+                    Collections2.filter(props.values(), modifiedFilter));
+        }
+
+        @Override
+        protected Iterable<String> internalGetChildNodeNames() {
+            Iterable<String> unmodified = base.getChildNodeNames();
+            Predicate<String> unmodifiedFilter =
+                    Predicates.not(Predicates.in(nodes.keySet()));
+            return Iterables.concat(
+                    Iterables.filter(unmodified, unmodifiedFilter),
+                    Maps.filterValues(nodes, Predicates.notNull()).keySet());
+        }
+
+        @Override
+        protected Iterable<? extends ChildNodeEntry> internalGetChildNodeEntries() {
+            Iterable<? extends ChildNodeEntry> unmodified =
+                    base.getChildNodeEntries();
+            Predicate<ChildNodeEntry> unmodifiedFilter =
+                    new SkipNamedNodes(nodes.keySet());
+            Map<String, MutableNodeState> modified =
+                    Maps.filterValues(nodes, Predicates.notNull());
+            return Iterables.concat(
+                    Iterables.filter(unmodified, unmodifiedFilter),
+                    MemoryChildNodeEntry.iterable(modified.entrySet()));
+        }
 
     }