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 mr...@apache.org on 2013/02/26 13:11:18 UTC

svn commit: r1450145 - /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java

Author: mreutegg
Date: Tue Feb 26 12:11:18 2013
New Revision: 1450145

URL: http://svn.apache.org/r1450145
Log:
OAK-643: Very high memory usage with 6000 child nodes 

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java?rev=1450145&r1=1450144&r2=1450145&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java Tue Feb 26 12:11:18 2013
@@ -21,9 +21,10 @@ package org.apache.jackrabbit.oak.kernel
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import javax.annotation.Nonnull;
@@ -80,7 +81,7 @@ public final class KernelNodeState exten
 
     private String id;
 
-    private Map<String, String> childPaths;
+    private Set<String> childNames;
 
     private final LoadingCache<String, KernelNodeState> cache;
 
@@ -114,7 +115,7 @@ public final class KernelNodeState exten
                 JsopReader reader = new JsopTokenizer(json);
                 reader.read('{');
                 properties = new LinkedHashMap<String, PropertyState>();
-                childPaths = new LinkedHashMap<String, String>();
+                childNames = new LinkedHashSet<String>();
                 do {
                     String name = StringCache.get(reader.readString());
                     reader.read(':');
@@ -135,11 +136,7 @@ public final class KernelNodeState exten
                         }
                     } else if (reader.matches('{')) {
                         reader.read('}');
-                        String childPath = path + '/' + name;
-                        if ("/".equals(path)) {
-                            childPath = '/' + name;
-                        }
-                        childPaths.put(name, childPath);
+                        childNames.add(name);
                     } else if (reader.matches('[')) {
                         properties.put(name, readArrayProperty(name, reader));
                     } else {
@@ -149,8 +146,8 @@ public final class KernelNodeState exten
                 reader.read('}');
                 reader.read(JsopReader.END);
                 // optimize for empty childNodes
-                if (childPaths.isEmpty()) {
-                    childPaths = Collections.emptyMap();
+                if (childNames.isEmpty()) {
+                    childNames = Collections.emptySet();
                 }
                 initialized = true;
             }
@@ -170,7 +167,11 @@ public final class KernelNodeState exten
             if (hashOrId != null) {
                 KernelNodeState cached = cache.getIfPresent(hashOrId);
                 if (cached != null && cached.path.equals(this.path)) {
-                    this.revision = cached.revision;
+                    synchronized (this) {
+                        this.revision = cached.revision;
+                        this.childNames = cached.childNames;
+                        this.properties = cached.properties;
+                    }
                 } else {
                     // store under secondary key
                     cache.put(hashOrId, this);
@@ -207,7 +208,10 @@ public final class KernelNodeState exten
     public NodeState getChildNode(String name) {
         checkNotNull(name);
         init();
-        String childPath = childPaths.get(name);
+        String childPath = null;
+        if (childNames.contains(name)) {
+            childPath = getChildPath(name);
+        }
         if (childPath == null && childNodeCount > MAX_CHILD_NODE_NAMES) {
             String path = getChildPath(name);
             // OAK-506: Avoid the nodeExists() call when already cached
@@ -231,11 +235,11 @@ public final class KernelNodeState exten
     @Override
     public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
         init();
-        Iterable<ChildNodeEntry> iterable = iterable(childPaths.entrySet());
-        if (childNodeCount > childPaths.size()) {
+        Iterable<ChildNodeEntry> iterable = iterable(childNames);
+        if (childNodeCount > childNames.size()) {
             List<Iterable<ChildNodeEntry>> iterables = Lists.newArrayList();
             iterables.add(iterable);
-            long offset = childPaths.size();
+            long offset = childNames.size();
             while (offset < childNodeCount) {
                 iterables.add(getChildNodeEntries(offset, MAX_CHILD_NODE_NAMES));
                 offset += MAX_CHILD_NODE_NAMES;
@@ -361,8 +365,7 @@ public final class KernelNodeState exten
                     reader.read(':');
                     if (reader.matches('{')) {
                         reader.read('}');
-                        String childPath = getChildPath(name);
-                        entries.add(new KernelChildNodeEntry(name, childPath));
+                        entries.add(new KernelChildNodeEntry(name));
                     } else if (reader.matches('[')) {
                         while (reader.read() != ']') {
                             // skip
@@ -387,12 +390,12 @@ public final class KernelNodeState exten
     }
 
     private Iterable<ChildNodeEntry> iterable(
-            Iterable<Entry<String, String>> set) {
+            Iterable<String> names) {
         return Iterables.transform(
-                set,
-                new Function<Entry<String, String>, ChildNodeEntry>() {
+                names,
+                new Function<String, ChildNodeEntry>() {
                     @Override
-                    public ChildNodeEntry apply(Entry<String, String> input) {
+                    public ChildNodeEntry apply(String input) {
                         return new KernelChildNodeEntry(input);
                     }
                 });
@@ -402,28 +405,13 @@ public final class KernelNodeState exten
 
         private final String name;
 
-        private final String path;
-
         /**
-         * Creates a child node entry with the given name and referenced
-         * child node state.
+         * Creates a child node entry with the given name.
          *
          * @param name child node name
-         * @param path child node path
          */
-        public KernelChildNodeEntry(String name, String path) {
+        public KernelChildNodeEntry(String name) {
             this.name = checkNotNull(name);
-            this.path = checkNotNull(path);
-        }
-
-        /**
-         * Utility constructor that copies the name and referenced
-         * child node state from the given map entry.
-         *
-         * @param entry map entry
-         */
-        public KernelChildNodeEntry(Map.Entry<String, String> entry) {
-            this(entry.getKey(), entry.getValue());
         }
 
         @Override
@@ -434,7 +422,7 @@ public final class KernelNodeState exten
         @Override
         public NodeState getNodeState() {
             try {
-                return cache.get(revision + path);
+                return cache.get(revision + getChildPath(name));
             } catch (ExecutionException e) {
                 throw new MicroKernelException(e);
             }