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/03/04 15:55:37 UTC
svn commit: r1452336 -
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
Author: mreutegg
Date: Mon Mar 4 14:55:36 2013
New Revision: 1452336
URL: http://svn.apache.org/r1452336
Log:
OAK-665: Excessive MK.nodeExists() calls with many 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=1452336&r1=1452335&r2=1452336&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 Mon Mar 4 14:55:36 2013
@@ -18,6 +18,9 @@
*/
package org.apache.jackrabbit.oak.kernel;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -31,6 +34,8 @@ import javax.annotation.Nonnull;
import javax.jcr.PropertyType;
import com.google.common.base.Function;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -67,6 +72,33 @@ public final class KernelNodeState exten
*/
static final int MAX_CHILD_NODE_NAMES = 1000;
+ /**
+ * Dummy cache instance for static {@link #NULL} kernel node state.
+ */
+ private static final LoadingCache<String, KernelNodeState> DUMMY_CACHE =
+ CacheBuilder.newBuilder().build(new CacheLoader<String, KernelNodeState>() {
+ @Override
+ public KernelNodeState load(String key) throws Exception {
+ throw new UnsupportedOperationException();
+ }
+ });
+
+ /**
+ * This <code>NULL</code> kernel node state is used as a value in the
+ * {@link #cache} to indicate that there is no node state at the given
+ * path and revision. This object is only used internally and never leaves
+ * this {@link KernelNodeState}.
+ */
+ private static final KernelNodeState NULL = new KernelNodeState(
+ (MicroKernel) Proxy.newProxyInstance(MicroKernel.class.getClassLoader(),
+ new Class[]{MicroKernel.class}, new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ throw new UnsupportedOperationException();
+ }
+ }), "null", "null", DUMMY_CACHE);
+
private final MicroKernel kernel;
private final String path;
@@ -221,9 +253,18 @@ public final class KernelNodeState exten
// OAK-506: Avoid the nodeExists() call when already cached
NodeState state = cache.getIfPresent(revision + path);
if (state != null) {
- return state;
- } else if (kernel.nodeExists(path, revision)) {
+ if (state != NULL) {
+ return state;
+ } else {
+ return null;
+ }
+ }
+ // not able to tell from cache if node exists
+ // need to ask MicroKernel
+ if (kernel.nodeExists(path, revision)) {
childPath = path;
+ } else {
+ cache.put(revision + path, NULL);
}
}
if (childPath == null) {