Author: mreutegg
Date: Tue Oct 24 11:18:05 2017
New Revision: 1813171

URL: http://svn.apache.org/viewvc?rev=1813171&view=rev
Log:
OAK-2621: Too many reads for child nodes

Added:
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1813171&r1=1813170&r2=1813171&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 Tue Oct 24 11:18:05 2017
@@ -268,16 +268,27 @@ public class DocumentNodeState extends A
             return bundledChildCount;
         }
 
-        if (max > DocumentNodeStore.NUM_CHILDREN_CACHE_LIMIT) {
-            // count all
-            return Iterables.size(getChildNodeEntries());
+        String name = null;
+        long count = 0;
+        int fetchSize = INITIAL_FETCH_SIZE;
+        long remaining = Math.max(max, 1); // fetch at least once
+        Children c = NO_CHILDREN;
+        while (remaining > 0) {
+            c = store.getChildren(this, name, fetchSize);
+            count += c.children.size();
+            remaining -= c.children.size();
+            if (!c.hasMore) {
+                break;
+            }
+            name = c.children.get(c.children.size() - 1);
+            fetchSize = Math.min(fetchSize << 1, MAX_FETCH_SIZE);
         }
-        Children c = store.getChildren(this, null, (int) max);
-        if (c.hasMore) {
-            return Long.MAX_VALUE;
-        } else {
+        if (!c.hasMore) {
             // we know the exact value
-            return c.children.size() + bundledChildCount;
+            return count + bundledChildCount;
+        } else {
+            // there are more than max
+            return Long.MAX_VALUE;
         }
     }
 

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1813171&r1=1813170&r2=1813171&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Tue Oct 24 11:18:05 2017
@@ -148,11 +148,6 @@ public final class DocumentNodeStore
     public static final FormatVersion VERSION = FormatVersion.V1_8;
 
     /**
-     * Do not cache more than this number of children for a document.
-     */
-    static final int NUM_CHILDREN_CACHE_LIMIT = 
Integer.getInteger("oak.documentMK.childrenCacheLimit", 16 * 1024);
-
-    /**
      * List of meta properties which are created by DocumentNodeStore and 
which needs to be
      * retained in any cloned copy of DocumentNodeState.
      */

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1813171&r1=1813170&r2=1813171&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 Tue Oct 24 11:18:05 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.document;
 
+import static com.google.common.collect.ImmutableList.of;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.synchronizedList;
 import static java.util.concurrent.TimeUnit.SECONDS;
@@ -52,6 +53,7 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
@@ -3549,7 +3551,6 @@ public class DocumentNodeStoreTest {
     }
 
     // OAK-2621
-    @Ignore("OAK-2621")
     @Test
     public void getChildNodeCount() throws Exception {
         CountingDocumentStore store = new CountingDocumentStore(new 
MemoryDocumentStore());
@@ -3573,6 +3574,56 @@ public class DocumentNodeStoreTest {
         assertEquals(1, store.getNumQueryCalls(NODES));
     }
 
+    @Test
+    public void getChildNodeCountTest() throws Exception {
+        final long UL = Long.MAX_VALUE; // unknown
+        // childNodeCount = none
+        getChildNodeCountTest(0,
+                of(0L, 1L),
+                of(0L, 0L)
+        );
+        // childNodeCount = less than initial fetch size 42
+        getChildNodeCountTest(42,
+                of( 0L,  1L, 41L, 42L, 43L, 100L),
+                of(42L, 42L, 42L, 42L, 42L, 42L)
+        );
+        // childNodeCount = initial fetch size (100)
+        getChildNodeCountTest(100,
+                of(  0L,   1L,  99L, 100L, 101L, 200L),
+                of(100L, 100L, 100L, 100L, 100L, 100L)
+        );
+        // childNodeCount = initial fetch size + 1 (100 + 1)
+        getChildNodeCountTest(101,
+                of(0L, 1L, 99L, 100L, 101L, 200L),
+                of(UL, UL,  UL,   UL, 101L, 101L)
+        );
+        // childNodeCount = first two fetches (100 + 200)
+        getChildNodeCountTest(300,
+                of(0L, 1L, 99L, 100L, 101L, 200L, 299L, 300L, 301L, 400L),
+                of(UL, UL,  UL,   UL, 300L, 300L, 300L, 300L, 300L, 300L)
+        );
+    }
+
+    private void getChildNodeCountTest(int numChildren,
+                                       Iterable<Long> maxValues,
+                                       Iterable<Long> expectedValues)
+            throws Exception {
+        DocumentNodeStore ns = builderProvider.newBuilder()
+                .setAsyncDelay(0).getNodeStore();
+        NodeBuilder builder = ns.getRoot().builder();
+        for (int i = 0; i < numChildren; i++) {
+            builder.child("test").child("node-" + i);
+        }
+        merge(ns, builder);
+        ns.getNodeChildrenCache().invalidateAll();
+
+        NodeState test = ns.getRoot().getChildNode("test");
+        Iterator<Long> expected = expectedValues.iterator();
+        for (long max : maxValues) {
+            assertEquals(expected.next().longValue(), 
test.getChildNodeCount(max));
+        }
+    }
+
     private static class WriteCountingStore extends MemoryDocumentStore {
         private final ThreadLocal<Boolean> createMulti = new ThreadLocal<>();
         int count;

Added: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java?rev=1813171&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java
 Tue Oct 24 11:18:05 2017
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.document;
+
+import javax.jcr.SimpleCredentials;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static 
org.apache.jackrabbit.oak.plugins.document.util.Utils.closeIfCloseable;
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertThat;
+
+public class GetChildNodeCountTest {
+
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new 
DocumentMKBuilderProvider();
+
+    private CountingDocumentStore store = new CountingDocumentStore(new 
MemoryDocumentStore());
+
+    private DocumentNodeStore ns;
+
+    private ContentRepository repository;
+
+    private ContentSession session;
+
+    @Before
+    public void before() throws Exception {
+        ns = builderProvider.newBuilder().setAsyncDelay(0)
+                .setDocumentStore(store).getNodeStore();
+        repository = new Oak(ns)
+                .with(new PropertyIndexEditorProvider())
+                .with(new OpenSecurityProvider())
+                .createContentRepository();
+        session = repository.login(new SimpleCredentials("admin", 
"admin".toCharArray()), null);
+        Root root = session.getLatestRoot();
+        Tree idx = root.getTree("/").addChild("oak:index").addChild("p");
+        idx.setProperty("type", "property");
+        idx.setProperty("propertyNames", newArrayList("p"), Type.NAMES);
+        root.commit();
+    }
+
+    @After
+    public void after() throws Exception {
+        session.close();
+        closeIfCloseable(repository);
+        ns.dispose();
+    }
+
+    @Test
+    public void removeIndexedNodes() throws Exception {
+        Root root = session.getLatestRoot();
+        Tree t = root.getTree("/").addChild("test");
+        for (int i = 0; i < 200; i ++) {
+            t.addChild("node-" + i).setProperty("p", "v");
+        }
+        root.commit();
+        ns.getNodeChildrenCache().invalidateAll();
+        store.resetCounters();
+        // remove nodes
+        root = session.getLatestRoot();
+        root.getTree("/test").remove();
+        root.commit();
+        assertThat(store.getNumQueryCalls(NODES), lessThan(13));
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/GetChildNodeCountTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to