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 ch...@apache.org on 2013/10/28 10:48:25 UTC

svn commit: r1536295 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/mongomk/ main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/ test/java/org/apache/jackrabbit/oak/plugins/mongomk/

Author: chetanm
Date: Mon Oct 28 09:48:24 2013
New Revision: 1536295

URL: http://svn.apache.org/r1536295
Log:
OAK-1117 - [MongoMk]Flag document with children

Adding support for marking nodes which have child nodes.
* Added DocumentStore.getIfCached replacing unused isCached
* Added a new boolean attribute `_hasChildNodes` to mark nodes which have child
* Modified Commit logic to mark parents by setting `_hasChildNodes` to true
* Changed assertion in two testcase as with this change the commit root might change
  in some cases

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/OptimizedChildFetchTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Commit.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MemoryDocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Node.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LoggingDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/Utils.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/SimpleTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Commit.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Commit.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Commit.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Commit.java Mon Oct 28 09:48:24 2013
@@ -20,12 +20,14 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.Sets;
 import org.apache.jackrabbit.mk.api.MicroKernelException;
 import org.apache.jackrabbit.mk.json.JsopStream;
 import org.apache.jackrabbit.mk.json.JsopWriter;
@@ -138,6 +140,7 @@ public class Commit {
      */
     void apply() {
         if (!operations.isEmpty()) {
+            updateParentChildStatus();
             applyToDocumentStore();
             applyToCache(false);
         }
@@ -145,6 +148,7 @@ public class Commit {
 
     void prepare(Revision baseRevision) {
         if (!operations.isEmpty()) {
+            updateParentChildStatus();
             applyToDocumentStore(baseRevision);
             applyToCache(true);
         }
@@ -269,6 +273,47 @@ public class Commit {
             throw new MicroKernelException(msg, e);
         }
     }
+
+    private void updateParentChildStatus() {
+        final DocumentStore store = nodeStore.getDocumentStore();
+        final Set<String> processedParents = Sets.newHashSet();
+        for (String path : addedNodes) {
+            if (PathUtils.denotesRoot(path)) {
+                continue;
+            }
+
+            String parentPath = PathUtils.getParentPath(path);
+
+            if (processedParents.contains(parentPath)) {
+                continue;
+            }
+
+            processedParents.add(parentPath);
+            final UpdateOp op = operations.get(parentPath);
+            if (op != null) {
+                //Parent node all ready part of modification list
+                //Update it in place
+                if (op.isNew()) {
+                    NodeDocument.setChildNodesStatus(op, true);
+                } else {
+                    NodeDocument nd = store.getIfCached(Collection.NODES, Utils.getIdFromPath(parentPath));
+                    if (nd != null && nd.hasChildNodes()) {
+                        continue;
+                    }
+                    NodeDocument.setChildNodesStatus(op, true);
+                }
+            } else {
+                NodeDocument nd = store.getIfCached(Collection.NODES, Utils.getIdFromPath(parentPath));
+                if (nd != null && nd.hasChildNodes()) {
+                    //Status already set to true. Nothing to do
+                    continue;
+                } else {
+                    UpdateOp updateParentOp = getUpdateOperationForNode(parentPath);
+                    NodeDocument.setChildNodesStatus(updateParentOp, true);
+                }
+            }
+        }
+    }
     
     private void rollback(ArrayList<UpdateOp> newDocuments, ArrayList<UpdateOp> changed) {
         DocumentStore store = nodeStore.getDocumentStore();

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentStore.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentStore.java Mon Oct 28 09:48:24 2013
@@ -176,13 +176,14 @@ public interface DocumentStore {
     void dispose();
 
     /**
-     * Check whether the given document is in the cache.
-     * 
+     * Fetches the cached document. If document is not present in cache <code>null</code> would be returned
+     *
      * @param <T> the document type
      * @param collection the collection
      * @param key the key
-     * @return true if yes
+     * @return cached document if present. Otherwise null
      */
-    <T extends Document> boolean isCached(Collection<T> collection, String key);
+    @CheckForNull
+    <T extends Document> T getIfCached(Collection<T> collection, String key);
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MemoryDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MemoryDocumentStore.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MemoryDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MemoryDocumentStore.java Mon Oct 28 09:48:24 2013
@@ -356,8 +356,8 @@ public class MemoryDocumentStore impleme
     }
 
     @Override
-    public <T extends Document> boolean isCached(Collection<T> collection, String key) {
-        return false;
+    public <T extends Document> T getIfCached(Collection<T> collection, String key) {
+        return find(collection,key);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java Mon Oct 28 09:48:24 2013
@@ -457,7 +457,7 @@ public class MongoDocumentStore implemen
             }
         } finally {
             end("create", start);
-        }        
+        }
     }
 
     @Override
@@ -516,6 +516,8 @@ public class MongoDocumentStore implemen
                     copy.put(key, o);
                 } else if (o instanceof Long) {
                     copy.put(key, o);
+                } else if (o instanceof Boolean) {
+                    copy.put(key, o);
                 } else if (o instanceof BasicDBObject) {
                     copy.put(key, convertMongoMap((BasicDBObject) o));
                 }
@@ -571,11 +573,11 @@ public class MongoDocumentStore implemen
     }
     
     @Override
-    public <T extends Document> boolean isCached(Collection<T> collection, String key) {
+    public <T extends Document> T getIfCached(Collection<T> collection, String key){
         if (collection != Collection.NODES) {
-            return false;
+            return null;
         }
-        return nodesCache.getIfPresent(key) != null;
+        return (T)nodesCache.getIfPresent(key);
     }
 
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java Mon Oct 28 09:48:24 2013
@@ -574,10 +574,6 @@ public class MongoMK implements MicroKer
         return nodeStore.getDocChildrenCacheStats();
     }
 
-    public boolean isCached(String path) {
-        return store.isCached(Collection.NODES, Utils.getIdFromPath(path));
-    }
-
     //------------------------------< internal >--------------------------------
 
     private void parseJsonDiff(Commit commit, String json, String rootPath) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java Mon Oct 28 09:48:24 2013
@@ -498,6 +498,14 @@ public final class MongoNodeStore
     public Node.Children getChildren(final String path, final Revision rev, final int limit)  throws
             MicroKernelException {
         checkRevisionAge(rev, path);
+
+        //Preemptive check. If we know there are no child then
+        //return straight away
+        final Node node = getNode(path,rev);
+        if(node.hasNoChildren()){
+            return new Node.Children();
+        }
+
         String key = path + "@" + rev;
         Node.Children children;
         try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Node.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Node.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Node.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Node.java Mon Oct 28 09:48:24 2013
@@ -29,7 +29,6 @@ import org.apache.jackrabbit.oak.plugins
  * Represents a node held in memory (in the cache for example).
  */
 public class Node implements CacheValue {
-
     /**
      * A node, which does not exist at a given revision.
      */
@@ -44,10 +43,16 @@ public class Node implements CacheValue 
     final Revision rev;
     final Map<String, String> properties = Utils.newMap();
     Revision lastRevision;
+    final boolean hasChildren;
     
     Node(String path, Revision rev) {
+       this(path,rev,false);
+    }
+
+    Node(String path, Revision rev,boolean hasChildren) {
         this.path = path;
         this.rev = rev;
+        this.hasChildren = hasChildren;
     }
     
     void setProperty(String propertyName, String value) {
@@ -70,6 +75,10 @@ public class Node implements CacheValue 
         newNode.properties.putAll(properties);
     }
 
+    public boolean hasNoChildren(){
+        return !hasChildren;
+    }
+
     @Override
     public String toString() {
         StringBuilder buff = new StringBuilder();
@@ -89,6 +98,7 @@ public class Node implements CacheValue 
         op.set(Document.ID, id);
         NodeDocument.setModified(op, rev);
         NodeDocument.setDeleted(op, rev, false);
+        NodeDocument.setChildNodesStatus(op,false);
         for (String p : properties.keySet()) {
             String key = Utils.escapePropertyName(p);
             op.setMapEntry(key, rev, properties.get(p));

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java Mon Oct 28 09:48:24 2013
@@ -34,6 +34,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.oak.cache.CacheValue;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.Utils;
@@ -125,11 +126,18 @@ public class NodeDocument extends Docume
     private static final String LAST_REV = "_lastRev";
 
     /**
+     * Flag indicating that there are child nodes present. Its just used as a hint.
+     * If false then that indicates that there are no child. However if its true its
+     * not necessary that there are child nodes. It just means at some moment this
+     * node had a child node
+     */
+    private static final String HAS_CHILD_NODE = "_hasChildNodes";
+
+    /**
      * Properties to ignore when a document is split.
      */
-    private static final Set<String> IGNORE_ON_SPLIT =
-            Collections.unmodifiableSet(new HashSet<String>(
-                    Arrays.asList(ID, MOD_COUNT, MODIFIED, PREVIOUS, LAST_REV)));
+    private static final Set<String> IGNORE_ON_SPLIT = ImmutableSet.of(ID, MOD_COUNT, MODIFIED, PREVIOUS,
+            LAST_REV, HAS_CHILD_NODE);
 
     final DocumentStore store;
 
@@ -171,6 +179,13 @@ public class NodeDocument extends Docume
     }
 
     /**
+     * @return the approximate number of children for this node.
+     */
+    public boolean hasChildNodes() {
+        return checkNotNull((Boolean) get(HAS_CHILD_NODE)).booleanValue();
+    }
+
+    /**
      * @return a map of the last known revision for each clusterId.
      */
     @Nonnull
@@ -391,7 +406,7 @@ public class NodeDocument extends Docume
             return null;
         }
         String path = Utils.getPathFromId(getId());
-        Node n = new Node(path, readRevision);
+        Node n = new Node(path, readRevision, hasChildNodes());
         for (String key : keySet()) {
             if (!Utils.isPropertyName(key)) {
                 continue;
@@ -757,6 +772,11 @@ public class NodeDocument extends Docume
 
     //-------------------------< UpdateOp modifiers >---------------------------
 
+    public static void setChildNodesStatus(@Nonnull UpdateOp op,
+                                   boolean hasChildNode) {
+        checkNotNull(op).set(HAS_CHILD_NODE, Boolean.valueOf(hasChildNode));
+    }
+
     public static void setModified(@Nonnull UpdateOp op,
                                    @Nonnull Revision revision) {
         checkNotNull(op).set(MODIFIED, Commit.getModified(checkNotNull(revision).getTimestamp()));

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LoggingDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LoggingDocumentStoreWrapper.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LoggingDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LoggingDocumentStoreWrapper.java Mon Oct 28 09:48:24 2013
@@ -240,14 +240,14 @@ public class LoggingDocumentStoreWrapper
     }
 
     @Override
-    public <T extends Document> boolean isCached(final Collection<T> collection,
-                                                 final String key) {
+    public <T extends Document> T getIfCached(final Collection<T> collection,
+                                              final String key) {
         try {
             logMethod("isCached", collection, key);
-            return logResult(new Callable<Boolean>() {
+            return logResult(new Callable<T>() {
                 @Override
-                public Boolean call() throws Exception {
-                    return store.isCached(collection, key);
+                public T call() throws Exception {
+                    return store.getIfCached(collection, key);
                 }
             });
         } catch (Exception e) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingDocumentStoreWrapper.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingDocumentStoreWrapper.java Mon Oct 28 09:48:24 2013
@@ -275,10 +275,10 @@ public class TimingDocumentStoreWrapper 
     }
 
     @Override
-    public <T extends Document> boolean isCached(Collection<T> collection, String key) {
+    public <T extends Document> T getIfCached(Collection<T> collection, String key) {
         try {
             long start = now();
-            boolean result = base.isCached(collection, key);
+            T result = base.getIfCached(collection, key);
             updateAndLogTimes("isCached", start, 0, 0);
             return result;
         } catch (Exception e) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/Utils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/Utils.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/Utils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/Utils.java Mon Oct 28 09:48:24 2013
@@ -94,6 +94,8 @@ public class Utils {
                 size += 48 + ((String) o).length() * 2;
             } else if (o instanceof Long) {
                 size += 16;
+            } else if (o instanceof Boolean) {
+                size += 8;
             } else if (o instanceof Integer) {
                 size += 8;
             } else if (o instanceof Map) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java Mon Oct 28 09:48:24 2013
@@ -195,7 +195,7 @@ public class DocumentSplitTest extends B
         Map<Revision, String> revs = doc.getLocalRevisions();
         assertEquals(3, revs.size());
         revs = doc.getValueMap("_revisions");
-        assertEquals(3 * NodeDocument.REVISIONS_SPLIT_OFF_SIZE + 1, revs.size());
+        assertEquals(3 * NodeDocument.REVISIONS_SPLIT_OFF_SIZE, revs.size());
         Revision previous = null;
         for (Map.Entry<Revision, String> entry : revs.entrySet()) {
             if (previous != null) {

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/OptimizedChildFetchTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/OptimizedChildFetchTest.java?rev=1536295&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/OptimizedChildFetchTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/OptimizedChildFetchTest.java Mon Oct 28 09:48:24 2013
@@ -0,0 +1,113 @@
+/*
+ * 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.mongomk;
+
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.plugins.mongomk.util.Utils;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Set;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.matchers.JUnitMatchers.hasItem;
+
+
+public class OptimizedChildFetchTest extends BaseMongoMKTest {
+
+    private TestDocumentStore ds = new TestDocumentStore();
+
+    @Before
+    public void initMongoMK() {
+        mk = new MongoMK.Builder().setDocumentStore(ds).open();
+    }
+
+    @Test
+    public void checkForChildStatusFlag() {
+        String head = mk.getHeadRevision();
+        mk.commit("",
+                "+\"/root\":{}\n" +
+                        "+\"/root/a\":{}\n" +
+                        "+\"/root/a/b\":{}\n",
+                head, "");
+
+        assertTrue(getChildStatus("/root"));
+        assertTrue(getChildStatus("/root/a"));
+        assertFalse(getChildStatus("/root/a/b"));
+    }
+
+    @Test
+    public void checkForNoCallsToFetchChildForLeafNodes() {
+        String head = mk.getHeadRevision();
+        String rev = mk.commit("",
+                "+\"/root\":{}\n" +
+                        "+\"/root/a\":{}\n" +
+                        "+\"/root/c\":{}\n" +
+                        "+\"/root/a/b\":{}\n",
+                head, "");
+
+        //Clear the caches
+        ds.paths.clear();
+        resetMK();
+
+        //Check that call is made to fetch child for non
+        //leaf nodes
+        mk.getNodes("/root/a", rev, 0, 0, 10, null);
+        assertThat(ds.paths, hasItem("3:/root/a/"));
+
+        resetMK();
+        ds.paths.clear();
+
+        //Check that no query is made to fetch children for
+        //leaf nodes
+        assertNotNull(mk.getNodes("/root/c", rev, 0, 0, 10, null));
+        assertNotNull(mk.getNodes("/root/a/b", rev, 0, 0, 10, null));
+        assertTrue(ds.paths.isEmpty());
+    }
+
+    private void resetMK() {
+        disposeMongoMK();
+        initMongoMK();
+
+    }
+
+    private boolean getChildStatus(String path) {
+        NodeDocument nd = mk.getDocumentStore().find(Collection.NODES, Utils.getIdFromPath(path));
+        return nd.hasChildNodes();
+    }
+
+
+    private static class TestDocumentStore extends MemoryDocumentStore {
+        Set<String> paths = Sets.newHashSet();
+
+        @Nonnull
+        @Override
+        public <T extends Document> List<T> query(Collection<T> collection, String fromKey, String toKey,
+                                                  String indexedProperty, long startValue, int limit) {
+            paths.add(fromKey);
+            return super.query(collection, fromKey, toKey, indexedProperty, startValue, limit);
+        }
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/SimpleTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/SimpleTest.java?rev=1536295&r1=1536294&r2=1536295&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/SimpleTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/SimpleTest.java Mon Oct 28 09:48:24 2013
@@ -388,20 +388,23 @@ public class SimpleTest {
 
             // root node must not have the revision
             NodeDocument rootDoc = store.find(Collection.NODES, "0:/");
-            assertNotNull(rootDoc);
-            assertFalse(rootDoc.containsRevision(head));
+
+            //As we update the childStatus flag the commit root would shift
+            //one layer above
+            // assertNotNull(rootDoc);
+            // assertFalse(rootDoc.containsRevision(head));
 
             // test node must have head in revisions
             NodeDocument node = store.find(Collection.NODES, "1:/test");
-            assertNotNull(node);
-            assertTrue(node.containsRevision(head));
+            //assertNotNull(node);
+            //assertTrue(node.containsRevision(head));
 
             // foo must not have head in revisions and must refer to test
             // as commit root (depth = 1)
             NodeDocument foo = store.find(Collection.NODES, "2:/test/foo");
             assertNotNull(foo);
             assertFalse(foo.containsRevision(head));
-            assertEquals("/test", foo.getCommitRootPath(head));
+            assertEquals("/", foo.getCommitRootPath(head));
 
             head = Revision.fromString(mk.commit("", "+\"/bar\":{}+\"/test/foo/bar\":{}", head.toString(), null));