You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/01/19 20:23:34 UTC

svn commit: r1233545 - in /jackrabbit/sandbox/microkernel/src: main/java/org/apache/jackrabbit/mk/mem/ test/java/org/apache/jackrabbit/mk/ test/java/org/apache/jackrabbit/mk/large/ test/java/org/apache/jackrabbit/mk/mem/

Author: thomasm
Date: Thu Jan 19 19:23:33 2012
New Revision: 1233545

URL: http://svn.apache.org/viewvc?rev=1233545&view=rev
Log:
Support large sorted child node lists.

Added:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListTrie.java
Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/MultiMkTestBase.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/mem/MemoryNodeTest.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java?rev=1233545&r1=1233544&r2=1233545&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java Thu Jan 19 19:23:33 2012
@@ -60,19 +60,18 @@ public class NodeImpl implements Cache.V
     public static final String HASH = ":hash";
 
     /**
-     * Used by NodeListLarge when there are many child nodes.
+     * Used when there are many child nodes.
      * The id of an internal node.
      */
     static final String CHILDREN = ":children";
 
     /**
-     * Used by NodeListLarge when there are many child nodes.
-     * The name bloom filter for a internal node.
+     * Used when there are many child nodes.
      */
     static final String NAMES = ":names";
 
     /**
-     * Used by NodeListLarge when there are many child nodes.
+     * Used when there are many child nodes.
      * The number of child nodes for an internal node.
      */
     static final String COUNT = ":childCount";
@@ -624,7 +623,11 @@ public class NodeImpl implements Cache.V
                 String value = t.readRawValue();
                 if (key.length() > 0 && key.charAt(0) == ':') {
                     if (key.equals(CHILDREN)) {
-                        node.childNodes = NodeListLarge.read(t, map, value);
+                        if (MemoryKernelImpl.SORT_CHILDREN) {
+                            node.childNodes = NodeListTrie.read(t, map, value);
+                        } else {
+                            node.childNodes = NodeListLarge.read(t, map, value);
+                        }
                     } else if (key.equals(DESCENDANT_COUNT)) {
                         node.descendantCount = Long.parseLong(value);
                         descendantCountSet = true;

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java?rev=1233545&r1=1233544&r2=1233545&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java Thu Jan 19 19:23:33 2012
@@ -198,7 +198,11 @@ public class NodeListSmall implements No
     public NodeList createClone(NodeMap map, long revId) {
         NodeList result = new NodeListSmall(names, children, sort, size);
         if (size > map.getMaxMemoryChildren()) {
-            return new NodeListLarge(map, result, size, revId);
+            if (MemoryKernelImpl.SORT_CHILDREN) {
+                return new NodeListTrie(map, result, size, revId);
+            } else {
+                return new NodeListLarge(map, result, size, revId);
+            }
         }
         return result;
     }

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListTrie.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListTrie.java?rev=1233545&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListTrie.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListTrie.java Thu Jan 19 19:23:33 2012
@@ -0,0 +1,359 @@
+/*
+ * 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.mk.mem;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.apache.jackrabbit.mk.json.JsopTokenizer;
+import org.apache.jackrabbit.mk.json.JsopWriter;
+import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
+import org.apache.jackrabbit.mk.util.IOUtils;
+
+/**
+ * A large list of nodes, using a data structure similar to a trie.
+ */
+public class NodeListTrie implements NodeList {
+
+    ArrayList<Child> children;
+    private final int prefixLength;
+
+    private final NodeMap map;
+    private final long revId;
+    private long size;
+
+    private NodeListTrie(NodeMap map, ArrayList<Child> children, int prefixLength, long revId) {
+        this.map = map;
+        this.children = children;
+        this.prefixLength = prefixLength;
+        this.revId = revId;
+        for (Child c : children) {
+            size += getList(c, false).size();
+        }
+    }
+
+    NodeListTrie(NodeMap map, NodeList list, long size, long revId) {
+        this.map = map;
+        this.children = new ArrayList<Child>();
+        this.revId = revId;
+        int len = 0;
+        for (int j = 0; len == 0; j++) {
+            String last = null;
+            for (long i = 0;; i++) {
+                String n = list.getName(i);
+                if (n == null) {
+                    break;
+                }
+                String p = getPrefix(n, j);
+                if (last == null) {
+                    last = p;
+                } else if (!p.equals(last)) {
+                    len = j;
+                    break;
+                }
+            }
+        }
+        this.prefixLength = len;
+        String last = null;
+        NodeListSmall partList = new NodeListSmall();
+        for (long i = 0;; i++) {
+            String n = list.getName(i);
+            if (n == null) {
+                break;
+            }
+            String p = getPrefix(n, len);
+            if (last == null || p.equals(last)) {
+                partList.add(n, list.get(n));
+                last = p;
+            } else {
+                addChild(children.size(), last, partList);
+                partList = new NodeListSmall();
+                partList.add(n, list.get(n));
+                last = p;
+            }
+        }
+        addChild(children.size(), last, partList);
+        this.size = size;
+    }
+
+    private String getPrefix(String name, int len) {
+        if (name.length() < len) {
+            return name + new String(new char[len - name.length()]);
+        }
+        return name.substring(0, len);
+    }
+
+    private void addChild(int index, String name, NodeListSmall partList) {
+        if (partList.size == 0) {
+            return;
+        }
+        Child c = new Child();
+        c.prefix = getPrefix(name, prefixLength);
+        NodeImpl n = new NodeImpl(map, revId);
+        n.setNodeList(partList);
+        c.id = map.addNode(n);
+        children.add(index, c);
+    }
+
+    public boolean containsKey(String name) {
+        int index = getChildIndex(name);
+        if (index < 0) {
+            return false;
+        }
+        Child c = children.get(index);
+        NodeList list = getList(c, true);
+        return list.containsKey(name);
+    }
+
+    NodeList getList(Child c, boolean modify) {
+        NodeImpl n = c.id.getNode(map);
+        if (modify) {
+            n = n.createClone(revId);
+            c.id = map.addNode(n);
+        }
+        return n.getNodeList();
+    }
+
+    public NodeId get(String name) {
+        int index = getChildIndex(name);
+        if (index < 0) {
+            index = -index - 1;
+        }
+        Child c = children.get(index);
+        NodeList list = getList(c, true);
+        return list.get(name);
+    }
+
+    public String getName(long pos) {
+        int i = 0;
+        for (; i < children.size(); i++) {
+            Child c = children.get(i);
+            long size = getList(c, false).size();
+            if (size > pos) {
+                NodeList list = getList(c, false);
+                return list.getName(pos);
+            }
+            pos -= size;
+        }
+        return null;
+    }
+
+    public Iterator<String> getNames(long offset, final int maxCount) {
+        int i = 0;
+        for (; i < children.size(); i++) {
+            Child c = children.get(i);
+            long size = getList(c, false).size();
+            if (size > offset) {
+                break;
+            }
+            offset -= size;
+        }
+        final int start = i;
+        final long off = offset;
+        Iterator<String> it = new Iterator<String>() {
+            int pos = start;
+            int remaining = maxCount;
+            long offset = off;
+            Iterator<String> it;
+            public boolean hasNext() {
+                if (it != null && it.hasNext()) {
+                    return true;
+                }
+                while (pos < children.size()) {
+                    it = getList(children.get(pos++), false).getNames(offset, remaining);
+                    offset = 0;
+                    if (it.hasNext()) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            public String next() {
+                if (hasNext()) {
+                    remaining--;
+                    return it.next();
+                } else {
+                    return null;
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+        return it;
+    }
+
+    private int getChildIndex(String name) {
+        String prefix = getPrefix(name, prefixLength);
+        int min = 0, max = children.size() - 1;
+        while (min <= max) {
+            int test = (min + max) >>> 1;
+            int compare = children.get(test).prefix.compareTo(prefix);
+            if (compare == 0) {
+                return test;
+            }
+            if (compare > 0) {
+                max = test - 1;
+            } else if (compare < 0) {
+                min = test + 1;
+            }
+        }
+        // not found: return negative insertion point
+        return -(min + 1);
+    }
+
+    public void add(String name, NodeId x) {
+        int index = getChildIndex(name);
+        if (index < 0) {
+            index = -index - 1;
+            NodeListSmall list = new NodeListSmall();
+            list.add(name, x);
+            addChild(index, name, list);
+        } else {
+            Child c = children.get(index);
+            NodeList list = getList(c, true);
+            list.add(name, x);
+        }
+        size++;
+    }
+
+    public NodeId remove(String name) {
+        int index = getChildIndex(name);
+        if (index < 0) {
+            throw ExceptionFactory.get("Node not found: " + name);
+        }
+        Child c = children.get(index);
+        NodeList list = getList(c, true);
+        return list.remove(name);
+    }
+
+    public long size() {
+        return size;
+    }
+
+    static class Child {
+
+        NodeId id;
+        String prefix;
+
+        public String toString() {
+            return prefix;
+        }
+
+    }
+
+    public NodeList createClone(NodeMap map, long revId) {
+        if (revId == this.revId) {
+            return this;
+        }
+        if (size < map.getMaxMemoryChildren() / 2) {
+            NodeListSmall s = new NodeListSmall();
+            for (Iterator<String> it = getNames(0, Integer.MAX_VALUE); it.hasNext();) {
+                String n = it.next();
+                s.add(n, get(n));
+            }
+            return s;
+        }
+        ArrayList<Child> newChildren = new ArrayList<Child>();
+        int len = 0;
+        for (Child c : children) {
+            Child c2 = new Child();
+            c2.id = map.addNode(c.id.getNode(map));
+            c2.prefix = c.prefix;
+            len = Math.max(len, c.prefix.length());
+            newChildren.add(c2);
+        }
+        NodeListTrie result = new NodeListTrie(map, newChildren, len, revId);
+        if (children.size() > map.getMaxMemoryChildren()) {
+            return new NodeListTrie(map, result, size, revId);
+        }
+        return result;
+    }
+
+    public void visit(ChildVisitor v) {
+        for (Child c : children) {
+            v.accept(c.id);
+        }
+    }
+
+    public void append(JsopWriter json, NodeMap map) {
+        for (Child c : children) {
+            json.key(NodeImpl.CHILDREN);
+            NodeId x = c.id;
+            NodeId y = map.getId(x);
+            if (x != y) {
+                c.id = y;
+            }
+            json.encodedValue(map.formatId(y));
+            json.key(NodeImpl.NAMES).value(c.prefix);
+        }
+        json.key(NodeImpl.COUNT).value(size);
+    }
+
+    static NodeListTrie read(JsopTokenizer t, NodeMap map, String value) {
+        Child c = new Child();
+        c.id = map.parseId(value);
+        ArrayList<Child> children = new ArrayList<Child>();
+        children.add(c);
+        int len = 0;
+        long size = 0;
+        while (t.matches(',')) {
+            String k = t.readString();
+            t.read(':');
+            if (k.endsWith(NodeImpl.COUNT)) {
+                size = Long.parseLong(t.readRawValue());
+            } else if (k.equals(NodeImpl.CHILDREN)) {
+                value = t.readRawValue();
+                c = new Child();
+                c.id = map.parseId(value);
+                children.add(c);
+            } else if (k.equals(NodeImpl.NAMES)) {
+                c.prefix = t.readString();
+                len = Math.max(len, c.prefix.length());
+            } else {
+                throw ExceptionFactory.get("Unexpected " + k);
+            }
+        }
+        NodeListTrie list = new NodeListTrie(map, children, len, 0);
+        list.size = size;
+        return list;
+    }
+
+    public int getMemory() {
+        return children.size() * 100;
+    }
+
+    public void updateHash(NodeMap map, OutputStream out) throws IOException {
+        for (Child c : children) {
+            byte[] hash = c.id.getHash();
+            IOUtils.writeString(out, c.prefix);
+            if (hash == null) {
+                hash = map.getNode(c.id.getLong()).getHash();
+            }
+            out.write(hash);
+        }
+    }
+
+    public byte[] getNameFilter(NodeMap map) {
+        return null;
+    }
+
+}

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/MultiMkTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/MultiMkTestBase.java?rev=1233545&r1=1233544&r2=1233545&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/MultiMkTestBase.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/MultiMkTestBase.java Thu Jan 19 19:23:33 2012
@@ -48,10 +48,10 @@ public class MultiMkTestBase {
     @Parameters
     public static Collection<Object[]> urls() {
             return Arrays.asList(new Object[][]{
-//                    {"fs:{homeDir}/target"},
+                    {"fs:{homeDir}/target"},
                     {"mem:"},
-//                    {"mem:fs:target/temp"},
-//                    {"http-bridge:fs:{homeDir}/target"}
+                    {"mem:fs:target/temp"},
+                    {"http-bridge:fs:{homeDir}/target"}
                     });
     }
 
@@ -140,7 +140,7 @@ public class MultiMkTestBase {
         }
     }
 
-    boolean areChildrenSorted() {
+    public boolean areChildrenSorted() {
         if (isMemoryKernel(mk)) {
             return MemoryKernelImpl.SORT_CHILDREN;
         }

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java?rev=1233545&r1=1233544&r2=1233545&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java Thu Jan 19 19:23:33 2012
@@ -92,10 +92,9 @@ public class LargeNodeTest extends Multi
         }
         head = mk.commit("/", "+ \"test\": {}", head, "");
 
-        // added 100000 nodes (1438 nodes/second)
-        // added 100000 nodes (18611 nodes/second)
-        int count = 5000;
+        // added 1000000 nodes 33.93 seconds (1000000 ops; 29471 op/s)
         // int count = 1000000;
+        int count = 5000;
         StopWatch timer = new StopWatch();
         StringBuilder buff = new StringBuilder();
         for (int i = 0; i < count; i++) {
@@ -130,31 +129,71 @@ public class LargeNodeTest extends Multi
         for (int i = 0; i < 100; i++) {
             head = mk.commit("/", "+ \"t" + i + "\": {\"x\":" + i + "}", head, "");
         }
-        Assert.assertEquals("{\":childNodeCount\":101,\"t\":{\":childNodeCount\":3,\"a\":{},\"b\":{},\"c\":{}}," +
-                "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
-                "\"t1\":{\"x\":1,\":childNodeCount\":0}," +
-                "\"t2\":{\"x\":2,\":childNodeCount\":0}," +
-                "\"t3\":{\"x\":3,\":childNodeCount\":0}," +
-                "\"t4\":{\"x\":4,\":childNodeCount\":0}," +
-                "\"t5\":{\"x\":5,\":childNodeCount\":0}," +
-                "\"t6\":{\"x\":6,\":childNodeCount\":0}," +
-                "\"t7\":{\"x\":7,\":childNodeCount\":0}," +
-                "\"t8\":{\"x\":8,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 0, -1));
-        Assert.assertEquals("{\":childNodeCount\":101," +
-                "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
-                "\"t1\":{\"x\":1,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 1, 2));
-        Assert.assertEquals("{\":childNodeCount\":101," +
-                "\"t9\":{\"x\":9,\":childNodeCount\":0}," +
-                "\"t10\":{\"x\":10,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 10, 2));
-        Assert.assertEquals("{\":childNodeCount\":101," +
-                "\"t19\":{\"x\":19,\":childNodeCount\":0}," +
-                "\"t20\":{\"x\":20,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 20, 2));
-        Assert.assertEquals("{\":childNodeCount\":101," +
-                "\"t39\":{\"x\":39,\":childNodeCount\":0}," +
-                "\"t40\":{\"x\":40,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 40, 2));
-        Assert.assertEquals("{\":childNodeCount\":101," +
-                "\"t89\":{\"x\":89,\":childNodeCount\":0}," +
-                "\"t90\":{\"x\":90,\":childNodeCount\":0}}", mk.getNodes("/", head, 1, 90, 2));
+        if (areChildrenSorted()) {
+            Assert.assertEquals("{\":childNodeCount\":101,\"t\":{\":childNodeCount\":3,\"a\":{},\"b\":{},\"c\":{}}," +
+                    "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
+                    "\"t1\":{\"x\":1,\":childNodeCount\":0}," +
+                    "\"t10\":{\"x\":10,\":childNodeCount\":0}," +
+                    "\"t11\":{\"x\":11,\":childNodeCount\":0}," +
+                    "\"t12\":{\"x\":12,\":childNodeCount\":0}," +
+                    "\"t13\":{\"x\":13,\":childNodeCount\":0}," +
+                    "\"t14\":{\"x\":14,\":childNodeCount\":0}," +
+                    "\"t15\":{\"x\":15,\":childNodeCount\":0}," +
+                    "\"t16\":{\"x\":16,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 0, -1));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
+                    "\"t1\":{\"x\":1,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 1, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t17\":{\"x\":17,\":childNodeCount\":0}," +
+                    "\"t18\":{\"x\":18,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 10, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t26\":{\"x\":26,\":childNodeCount\":0}," +
+                    "\"t27\":{\"x\":27,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 20, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t44\":{\"x\":44,\":childNodeCount\":0}," +
+                    "\"t45\":{\"x\":45,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 40, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t9\":{\"x\":9,\":childNodeCount\":0}," +
+                    "\"t90\":{\"x\":90,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 90, 2));
+        } else {
+            Assert.assertEquals("{\":childNodeCount\":101,\"t\":{\":childNodeCount\":3,\"a\":{},\"b\":{},\"c\":{}}," +
+                    "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
+                    "\"t1\":{\"x\":1,\":childNodeCount\":0}," +
+                    "\"t2\":{\"x\":2,\":childNodeCount\":0}," +
+                    "\"t3\":{\"x\":3,\":childNodeCount\":0}," +
+                    "\"t4\":{\"x\":4,\":childNodeCount\":0}," +
+                    "\"t5\":{\"x\":5,\":childNodeCount\":0}," +
+                    "\"t6\":{\"x\":6,\":childNodeCount\":0}," +
+                    "\"t7\":{\"x\":7,\":childNodeCount\":0}," +
+                    "\"t8\":{\"x\":8,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 0, -1));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t0\":{\"x\":0,\":childNodeCount\":0}," +
+                    "\"t1\":{\"x\":1,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 1, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t9\":{\"x\":9,\":childNodeCount\":0}," +
+                    "\"t10\":{\"x\":10,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 10, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t19\":{\"x\":19,\":childNodeCount\":0}," +
+                    "\"t20\":{\"x\":20,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 20, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t39\":{\"x\":39,\":childNodeCount\":0}," +
+                    "\"t40\":{\"x\":40,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 40, 2));
+            Assert.assertEquals("{\":childNodeCount\":101," +
+                    "\"t89\":{\"x\":89,\":childNodeCount\":0}," +
+                    "\"t90\":{\"x\":90,\":childNodeCount\":0}}",
+                    mk.getNodes("/", head, 1, 90, 2));
+        }
     }
 
     @Test

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/mem/MemoryNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/mem/MemoryNodeTest.java?rev=1233545&r1=1233544&r2=1233545&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/mem/MemoryNodeTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/mem/MemoryNodeTest.java Thu Jan 19 19:23:33 2012
@@ -62,11 +62,21 @@ public class MemoryNodeTest {
         n = n.cloneAndAddChildNode("c", false, null, c, 3);
         Assert.assertEquals("{\"a\":n1,\"b\":n2,\"c\":n3}", n.asString());
         n = n.cloneAndAddChildNode("d", false, null, d, 4);
-        Assert.assertEquals("{\":children\":n5,\":names\":\"0e00\",\":children\":n6,\":names\":\"1000\",\":childCount\":4}",
-                n.asString());
+        if (MemoryKernelImpl.SORT_CHILDREN) {
+            Assert.assertEquals("{\":children\":n5,\":names\":\"a\",\":children\":n6,\":names\":\"b\",\":children\":n7,\":names\":\"c\",\":children\":n8,\":names\":\"d\",\n\":childCount\":4}",
+                    n.asString());
+        } else {
+            Assert.assertEquals("{\":children\":n5,\":names\":\"0e00\",\":children\":n6,\":names\":\"1000\",\":childCount\":4}",
+                    n.asString());
+        }
         n2 = NodeImpl.fromString(map, n.asString());
-        Assert.assertEquals("{\":children\":n5,\":names\":\"0e00\",\":children\":n6,\":names\":\"1000\",\":childCount\":4}",
-                n2.asString());
+        if (MemoryKernelImpl.SORT_CHILDREN) {
+            Assert.assertEquals("{\":children\":n5,\":names\":\"a\",\":children\":n6,\":names\":\"b\",\":children\":n7,\":names\":\"c\",\":children\":n8,\":names\":\"d\",\n\":childCount\":4}",
+                    n2.asString());
+        } else {
+            Assert.assertEquals("{\":children\":n5,\":names\":\"0e00\",\":children\":n6,\":names\":\"1000\",\":childCount\":4}",
+                    n2.asString());
+        }
         Assert.assertTrue(n2.exists("a"));
         Assert.assertTrue(n2.exists("b"));
         Assert.assertTrue(n2.exists("c"));