jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r1574837 [2/2] - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/ind...
Date Thu, 06 Mar 2014 10:26:07 GMT
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,975 @@
+/*
+ * 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.index.property.strategy;
+
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy.NEXT;
+import static org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy.START;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+
+/**
+ *
+ */
+public class OrderedContentMirrorStorageStrategyTest {
+    /**
+     * ascending ordered set of keys. Useful for testing
+     */
+    private static final String[] KEYS = new String[] { "donald", "goofy", "mickey", "minnie" };
+    private static final Set<String> EMPTY_KEY_SET = newHashSet();
+
+    /**
+     * checks that the fist item/key is inserted with an empty property 'next'
+     * 
+     * expected structure:
+     * 
+     * <code>
+     * :index : {
+     *    :start : { :next=n0 },
+     *    n0 : { 
+     *       :next=,
+     *       foo : {
+     *          bar: { match=true}
+     *       }
+     *    }
+     * }
+     * </code>
+     */
+    @Test
+    public void firstAndOnlyItem() {
+        final String PATH = "/foo/bar";
+        final String[] PATH_NODES = Iterables.toArray(PathUtils.elements(PATH), String.class);
+        final String N0 = KEYS[0];
+
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        NodeBuilder node = null;
+
+        store.update(index, PATH, EMPTY_KEY_SET, newHashSet(N0));
+
+        assertFalse(":index should be left alone with not changes", index.hasProperty(NEXT));
+        node = index.getChildNode(START);
+        assertTrue(":index should have the :start node", node.exists());
+        assertEquals(":start should point to n0", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertTrue("n0 should exists in the index", node.exists());
+        assertEquals("n0 should point nowhere as it's the last (and only) element", "", node.getString(NEXT));
+
+        // checking content structure below n0
+        node = node.getChildNode(PATH_NODES[0]);
+        assertTrue("n0 should contain 'foo'", node.exists());
+        node = node.getChildNode(PATH_NODES[1]);
+        assertTrue("'foo' should contain 'bar'", node.exists());
+        assertTrue("the 'foo' node should have 'match=true'", node.getBoolean("match"));
+    }
+
+    /**
+     * test the saving of 2 new keys that comes already ordered
+     * 
+     * final state of the index will be
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next=n0 },
+     *       n0 : { :next=n1 },
+     *       n1 : { :next= }       
+     *    }
+     * </code>
+     */
+    @Test
+    public void first2newKeysAlreadyOrdered() {
+        final String PATH = "/foo/bar";
+        final String N0 = KEYS[0];
+        final String N1 = KEYS[1];
+
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        NodeBuilder node = null;
+
+        store.update(index, PATH, EMPTY_KEY_SET, newHashSet(N0)); // first node
+                                                                  // arrives
+
+        node = index.getChildNode(START);
+        assertTrue(":index should have :start", node.exists());
+        assertEquals(":start should point to n0", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertTrue(":index should have n0", node.exists());
+        assertEquals("n0 should point nowhere at this stage", "", node.getString(NEXT));
+
+        store.update(index, PATH, EMPTY_KEY_SET, newHashSet(N1)); // second node
+                                                                  // arrives
+
+        node = index.getChildNode(START);
+        assertTrue(":index should still have :start", node.exists());
+        assertEquals(":start should still point to n0", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertTrue("n0 should still exists", node.exists());
+        assertEquals("n0 should point to n1", N1, node.getString(NEXT));
+
+        node = index.getChildNode(N1);
+        assertTrue("n1 should exists", node.exists());
+        assertEquals("n1 should point nowhere", "", node.getString(NEXT));
+    }
+
+    /**
+     * Test the iteration of an empty index
+     */
+    @Test
+    public void childNodeEntriesEmptyIndex() {
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeState index = EmptyNodeState.EMPTY_NODE;
+
+        @SuppressWarnings("unchecked")
+        Iterable<ChildNodeEntry> children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(index);
+
+        assertNotNull("A returned Iterable cannot be null", children);
+    }
+
+    /**
+     * test the iteration of the index with 2 shuffled items
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next=n1 },
+     *       n0 : { :next= },
+     *       n1 : { :next=n0 }
+     *    }
+     * </code>
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void childNodeEntriesACoupleOfMixedItems() {
+        final String N0 = KEYS[1];
+        final String N1 = KEYS[0];
+        final NodeState NODE_0 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        final NodeState NODE_1 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, N0).getNodeState();
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+
+        // setting-up the index structure
+        index.child(START).setProperty(NEXT, N1);
+        index.setChildNode(N0, NODE_0);
+        index.setChildNode(N1, NODE_1);
+
+        NodeState indexState = index.getNodeState();
+
+        Iterable<ChildNodeEntry> children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState);
+        assertNotNull("The iterable cannot be null", children);
+        assertEquals("Expecting 2 items in the index", 2, Iterators.size(children.iterator())); 
+
+        // ensuring the right sequence
+        ChildNodeEntry entry = null;
+        children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState);
+        Iterator<ChildNodeEntry> it = children.iterator();
+        assertTrue("We should have 2 elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The first element should be n1", N1, entry.getName());
+        assertEquals("Wrong entry returned", NODE_1, entry.getNodeState());
+        assertTrue("We should have 1 elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The second element should be n0", N0, entry.getName());
+        assertEquals("Wrong entry returned", NODE_0, entry.getNodeState());
+        assertFalse("We should have be at the end of the list", it.hasNext());
+    }
+
+    /**
+     * test the iteration of the index with 2 shuffled items without the :start
+     * node
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next=n1 },
+     *       n0 : { :next= },
+     *       n1 : { :next=n0 }
+     *    }
+     * </code>
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void childNodeEntriesACoupleOfMixedItemsNoStart() {
+        final String N0 = KEYS[1];
+        final String N1 = KEYS[0];
+        final NodeState NODE_0 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        final NodeState NODE_1 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, N0).getNodeState();
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+
+        // setting-up the index structure
+        index.child(START).setProperty(NEXT, N1);
+        index.setChildNode(N0, NODE_0);
+        index.setChildNode(N1, NODE_1);
+
+        NodeState indexState = index.getNodeState();
+
+        Iterable<ChildNodeEntry> children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState, false);
+        assertNotNull("The iterable cannot be null", children);
+        assertEquals("Expecting 2 items in the index", 2, Iterators.size(children.iterator()));
+
+        // ensuring the right sequence
+        ChildNodeEntry entry = null;
+        children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState);
+        Iterator<ChildNodeEntry> it = children.iterator();
+        assertTrue("We should have 2 elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The first element should be n1", N1, entry.getName());
+        assertEquals("Wrong entry returned", NODE_1, entry.getNodeState());
+        assertTrue("We should have 1 elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The second element should be n0", N0, entry.getName());
+        assertEquals("Wrong entry returned", NODE_0, entry.getNodeState());
+        assertFalse("We should have be at the end of the list", it.hasNext());
+    }
+
+    /**
+     * test the iteration of the index with 2 shuffled items including the
+     * :start node as first
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next=n1 },
+     *       n0 : { :next= },
+     *       n1 : { :next=n0 }
+     *    }
+     * </code>
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void childNodeEntriesACoupleOfMixedItemsWithStart() {
+        final String N0 = KEYS[1];
+        final String N1 = KEYS[0];
+        final NodeState NODE_START = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, N1).getNodeState();
+        final NodeState NODE_0 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        final NodeState NODE_1 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, N0).getNodeState();
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+
+        // setting-up the index structure
+        index.setChildNode(START, NODE_START);
+        index.setChildNode(N0, NODE_0);
+        index.setChildNode(N1, NODE_1);
+
+        NodeState indexState = index.getNodeState();
+
+        Iterable<ChildNodeEntry> children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState, true);
+        assertNotNull("The iterable cannot be null", children);
+        assertEquals("Expecting 3 items in the index", 3, Iterators.size(children.iterator())); 
+
+        // ensuring the right sequence
+        ChildNodeEntry entry = null;
+        children = (Iterable<ChildNodeEntry>) store.getChildNodeEntries(indexState, true);
+        Iterator<ChildNodeEntry> it = children.iterator();
+        assertTrue("We should still have elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The first element should be :start", START, entry.getName());
+        assertEquals("Wrong entry returned", NODE_START, entry.getNodeState());
+        assertTrue("We should still have elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The second element should be n1", N1, entry.getName());
+        assertEquals("Wrong entry returned", NODE_1, entry.getNodeState());
+        assertTrue("We should still have elements left to loop through", it.hasNext());
+        entry = it.next();
+        assertEquals("The third element should be n0", N0, entry.getName());
+        assertEquals("Wrong entry returned", NODE_0, entry.getNodeState());
+        assertFalse("We should be at the end of the list", it.hasNext());
+    }
+
+    /**
+     * test the iteration over an empty list when the :start is required. In
+     * this case :start should always be returned
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next= }
+     *    }
+     * </code>
+     */
+    @Test
+    public void childNodeEntriesNoItemsWithStart() {
+        NodeState NODE_START = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        // setting-up the index
+        index.setChildNode(START, NODE_START);
+
+        Iterable<? extends ChildNodeEntry> children = store.getChildNodeEntries(index.getNodeState(), true);
+        assertEquals("Wrong size of Iterable", 1, Iterators.size(children.iterator()));
+
+        Iterator<? extends ChildNodeEntry> it = store.getChildNodeEntries(index.getNodeState(), true).iterator();
+        assertTrue("We should have at least 1 element", it.hasNext());
+        ChildNodeEntry entry = it.next();
+        assertEquals(":start is expected", START, entry.getName());
+        assertEquals("wrong node returned", NODE_START, entry.getNodeState());
+        assertFalse("We should be at the end of the list", it.hasNext());
+    }
+
+    /**
+     * test the case where we want an iterator for the children of a brand new
+     * index. In this case :start doesn't exists but if we ask for it we should
+     * return it.
+     */
+    @Test
+    public void childNodeEntriesNewIndexWithStart() {
+        NodeState NODE_START = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        Iterator<? extends ChildNodeEntry> children = store.getChildNodeEntries(index.getNodeState(), true).iterator();
+        assertEquals("Wrong number of children", 1, Iterators.size(children));
+
+        children = store.getChildNodeEntries(index.getNodeState(), true).iterator();
+        assertTrue("at least one item expected", children.hasNext());
+        ChildNodeEntry child = children.next();
+        assertEquals(START, child.getName());
+        assertEquals(NODE_START, child.getNodeState());
+        assertFalse(children.hasNext());
+    }
+
+    /**
+     * test the insert of two shuffled items
+     * 
+     * Building final a structure like
+     * 
+     * <code>
+     *    :index : {
+     *       :start : { :next=n1 },
+     *       n0 : { :next= },
+     *       n1 : { :next=n0 }
+     *    }
+     * </code>
+     * 
+     * where:
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     * 
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = 
+     *       }
+     *    }
+     * 
+     *    Stage 2
+     *    =======
+     * 
+     *    :index : {
+     *       :start : { :next = n1 },
+     *       n0 : {
+     *          :next =
+     *       },
+     *       n1 : {
+     *          :next = n0
+     *       }
+     *    }
+     * </code>
+     */
+    @Test
+    public void twoShuffledItems() {
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeState root = EmptyNodeState.EMPTY_NODE;
+        NodeBuilder index = root.builder();
+        String key1st = KEYS[1];
+        String key2nd = KEYS[0];
+        NodeState ns = null;
+
+        // Stage 1
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(key1st));
+        ns = index.getChildNode(START).getNodeState();
+        assertEquals(":start is expected to point to the 1st node", key1st, ns.getString(NEXT));
+        ns = index.getChildNode(key1st).getNodeState();
+        assertTrue("At Stage 1 the first node is expected to point nowhere as it's the last",
+                        Strings.isNullOrEmpty(ns.getString(NEXT)));
+
+        // Stage 2
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(key2nd));
+        ns = index.getChildNode(START).getNodeState();
+        assertEquals(":start is expected to point to the 2nd node", key2nd, ns.getString(NEXT));
+        ns = index.getChildNode(key1st).getNodeState();
+        assertTrue("At stage 2 the first element should point nowhere as it's the last",
+                        Strings.isNullOrEmpty(ns.getString(NEXT)));
+        ns = index.getChildNode(key2nd).getNodeState();
+        assertEquals("At Stage 2 the second element should point to the first one", key1st, ns.getString(NEXT));
+    }
+
+    /**
+     * test the insert of shuffled items
+     * 
+     * Building a final structure like
+     * 
+     * <code>
+     *    {
+     *       :start : { :next = n1 },
+     *       n0 : {
+     *          :next = ""
+     *       },
+     *       n1 : {
+     *          :next = n2
+     *       },
+     *       n2 : {
+     *          :next = n0
+     *       }
+     *    }
+     * </code>
+     * 
+     * where:
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     * 
+     *    {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = 
+     *       }
+     *    }
+     * 
+     *    Stage 2
+     *    =======
+     * 
+     *    {
+     *       :start : { :next = n1 },
+     *       n0 : { :next = },
+     *       n1 : { :next = n0 }
+     *    }
+     *    
+     *    Stage 3
+     *    =======
+     *    
+     *    {
+     *       :start : { :next = n1 },
+     *       n0 : { :next = },
+     *       n1 : { :next = n2 },
+     *       n2 : { :next = n0 }
+     *    }
+     *    
+     *    Stage 4
+     *    =======
+     * 
+     *    {
+     *       :start : { :next = n1 },
+     *       n0 : { :next = n3 },
+     *       n1 : { :next = n2 },
+     *       n2 : { :next = n0 },
+     *       n3 : { :next = }
+     *    }
+     * </code>
+     */
+    @Test
+    public void fourShuffledElements() {
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        String n0 = KEYS[2];
+        String n1 = KEYS[0];
+        String n2 = KEYS[1];
+        String n3 = KEYS[3];
+
+        // Stage 1
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        assertEquals(":start should point to the first node", n0, index.getChildNode(START).getString(NEXT));
+        assertTrue("the first node should point nowhere", Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+
+        // Stage 2
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+        assertEquals(":start should point to n1", n1, index.getChildNode(START).getString(NEXT));
+        assertEquals("'n1' should point to 'n0'", n0, index.getChildNode(n1).getString(NEXT));
+        assertTrue("n0 should still be point nowhere", Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+
+        // Stage 3
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
+        assertEquals(":start should point to n1", n1, index.getChildNode(START).getString(NEXT));
+        assertEquals("n1 should be pointing to n2", n2, index.getChildNode(n1).getString(NEXT));
+        assertEquals("n2 should be pointing to n0", n0, index.getChildNode(n2).getString(NEXT));
+        assertTrue("n0 should still be the last item of the list",
+                        Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+
+        // Stage 4
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
+        assertEquals(":start should point to n1", n1, index.getChildNode(START).getString(NEXT));
+        assertEquals("n1 should be pointing to n2", n2, index.getChildNode(n1).getString(NEXT));
+        assertEquals("n2 should be pointing to n0", n0, index.getChildNode(n2).getString(NEXT));
+        assertEquals("n0 should be pointing to n3", n3, index.getChildNode(n0).getString(NEXT));
+        assertTrue("n3 should be the last element", Strings.isNullOrEmpty(index.getChildNode(n3).getString(NEXT)));
+    }
+
+    /**
+     * perform a test where the index gets updated if an already existent
+     * node/key gets updated by changing the key and the key contains only 1
+     * item.
+     * 
+     * Where the second key is greater than the first.
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     *    
+     *    :index : {
+     *       :start { :next = n0 },
+     *       n0 : {
+     *          :next =,
+     *          content : {
+     *             foobar : {
+     *                match = true
+     *             }
+     *          }
+     *       }
+     *    }
+     *    
+     *    Stage 2
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n1 },
+     *       n1 : {
+     *          :next =,
+     *          content : {
+     *             foobar : {
+     *                match = true
+     *             }
+     *          }
+     *       }
+     *    }
+     * </code>
+     */
+
+    @Test
+    public void singleKeyUpdate() {
+        final String N0 = KEYS[0];
+        final String N1 = KEYS[1];
+        final String PATH = "/content/foobar";
+        final String[] NODES = Iterables.toArray(PathUtils.elements(PATH), String.class);
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        NodeBuilder node = null;
+
+        // Stage 1
+        store.update(index, PATH, EMPTY_KEY_SET, newHashSet(N0));
+        node = index.getChildNode(START);
+        assertTrue(":start should exists", node.exists());
+        assertEquals(":start should point to n0", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertTrue(":index should have n0", node.exists());
+        assertTrue("n0 should point nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+
+        node = node.getChildNode(NODES[0]);
+        assertTrue("n0 should have /content", node.exists());
+
+        node = node.getChildNode(NODES[1]);
+        assertTrue("/content should contain /foobar", node.exists());
+        assertTrue("/foobar should have match=true", node.getBoolean("match"));
+
+        // Stage 2
+        store.update(index, PATH, newHashSet(N0), newHashSet(N1));
+        node = index.getChildNode(START);
+        assertEquals(":start should now point to N1", N1, node.getString(NEXT));
+
+        node = index.getChildNode(N1);
+        assertTrue("N1 should exists", node.exists());
+        assertTrue("N1 should point nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+
+        node = node.getChildNode(NODES[0]);
+        assertTrue("N1 should have /content", node.exists());
+
+        node = node.getChildNode(NODES[1]);
+        assertTrue("/content should contain /foobar", node.exists());
+        assertTrue("/foobar should have match=true", node.getBoolean("match"));
+    }
+
+    /**
+     * <p>
+     * find a previous item given a key in an index with 1 element only
+     * </p>
+     * 
+     * <p>
+     * <i>it relies on the functionality of the store.update() for creating the
+     * index</i>
+     * </p>
+     * 
+     * <code>
+     *    :index {
+     *       :start : { :next=n0 },
+     *       n0 = { :next= }
+     *    }
+     * </code>
+     */
+    @Test
+    public void findPrevious1ItemIndex() {
+        final OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        final String N0 = KEYS[0];
+        final NodeState NODE_START = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, N0).getNodeState();
+        final NodeState NODE_0 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        final NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+
+        index.setChildNode(START, NODE_START);
+        index.setChildNode(N0, NODE_0);
+
+        NodeState indexState = index.getNodeState();
+        ChildNodeEntry previous = store.findPrevious(indexState, NODE_0);
+        assertNotNull(previous);
+        assertEquals("the :start node is expected", NODE_START, previous.getNodeState());
+    }
+
+    /**
+     * test the use case where a document change the indexed property. For
+     * example document that change author.
+     * 
+     * <p>
+     * <i>it relies on the functionality of the store.update() for creating the
+     * index</i>
+     * </p>
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = ,
+     *          content : {
+     *             one { match=true },
+     *             two { match=true }
+     *          }
+     *       }
+     *    }
+     *    
+     *    Stage 2
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = n1,
+     *          content : {
+     *             one : { match = true }
+     *          }
+     *       },
+     *       n1 : {
+     *          :next = ,
+     *          content : {
+     *             two : { match = true }
+     *          }
+     *       }
+     *    }
+     * </code>
+     */
+    @Test
+    public void documentChangingKey() {
+        final String PATH0 = "/content/one";
+        final String PATH1 = "/content/two";
+        final String N0 = KEYS[0];
+        final String N1 = KEYS[1];
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        // Stage 1 - initialising the index
+        store.update(index, PATH0, EMPTY_KEY_SET, newHashSet(N0));
+        store.update(index, PATH1, EMPTY_KEY_SET, newHashSet(N0));
+
+        // ensuring the right structure
+        assertTrue(index.hasChildNode(START));
+        assertTrue(index.hasChildNode(N0));
+        assertFalse(index.hasChildNode(N1));
+
+        NodeBuilder node = index.getChildNode(START);
+        assertEquals(":start pointing to wrong node", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertTrue("N0 should go nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+
+        // checking the first document
+        String[] path = Iterables.toArray(PathUtils.elements(PATH0), String.class);
+        node = node.getChildNode(path[0]);
+        assertTrue(node.exists());
+        node = node.getChildNode(path[1]);
+        assertTrue(node.exists());
+        assertTrue(node.getBoolean("match"));
+
+        path = Iterables.toArray(PathUtils.elements(PATH0), String.class);
+        node = index.getChildNode(N0).getChildNode(path[0]);
+        assertTrue(node.exists());
+        node = node.getChildNode(path[1]);
+        assertTrue(node.exists());
+        assertTrue(node.getBoolean("match"));
+
+        // Stage 2
+        store.update(index, PATH1, newHashSet(N0), newHashSet(N1));
+        assertTrue(index.hasChildNode(START));
+        assertTrue(index.hasChildNode(N0));
+        assertTrue(index.hasChildNode(N1));
+
+        node = index.getChildNode(START);
+        assertEquals(":start pointing to wrong node", N0, node.getString(NEXT));
+
+        node = index.getChildNode(N0);
+        assertEquals(N1, node.getString(NEXT));
+        path = Iterables.toArray(PathUtils.elements(PATH0), String.class);
+        node = node.getChildNode(path[0]);
+        assertTrue(node.exists());
+        node = node.getChildNode(path[1]);
+        assertTrue(node.exists());
+        assertTrue(node.getBoolean("match"));
+        path = Iterables.toArray(PathUtils.elements(PATH1), String.class);
+        node = index.getChildNode(N0).getChildNode(path[0]);// we know both the
+                                                            // documents share
+                                                            // the same /content
+        assertFalse("/content/two should no longer be under N0", node.hasChildNode(path[1]));
+
+        node = index.getChildNode(N1);
+        assertTrue("N1 should point nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+        path = Iterables.toArray(PathUtils.elements(PATH1), String.class);
+        node = node.getChildNode(path[0]);
+        assertTrue(node.exists());
+        node = node.getChildNode(path[1]);
+        assertTrue(node.exists());
+        assertTrue(node.getBoolean("match"));
+    }
+
+    /**
+     * test when a document is deleted and is the only one under the indexed key
+     * 
+     * <p>
+     * <i>it relies on the functionality of the store.update() for creating the
+     * index</i>
+     * </p>
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = ,
+     *          sampledoc : { match = true }
+     *       }
+     *    }
+     *    
+     *    Stage 2
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = }
+     *    }
+     * </code>
+     */
+    @Test
+    public void deleteTheOnlyDocument() {
+        final String N0 = KEYS[0];
+        final String PATH = "/sampledoc";
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        // Stage 1 - initialising the index
+        store.update(index, PATH, EMPTY_KEY_SET, newHashSet(N0));
+
+        // we assume it works and therefore not checking the status of the index
+        // let's go straight to Stage 2
+
+        // Stage 2
+        store.update(index, PATH, newHashSet(N0), EMPTY_KEY_SET);
+        assertFalse("The node should have been removed", index.hasChildNode(N0));
+        assertTrue("as the index should be empty, :start should point nowhere",
+                        Strings.isNullOrEmpty(index.getChildNode(START).getString(NEXT)));
+    }
+
+    /**
+     * test when the document is deleted but there're still some documents left
+     * under the indexed key
+     * 
+     * <p>
+     * <i>it relies on the functionality of the store.update() for creating the
+     * index</i>
+     * </p>
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next = ,
+     *          doc1 : { match=true },
+     *          doc2 : { match=true }
+     *       }
+     *    }
+     *    
+     *    Stage 2
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n0 },
+     *       n0 : {
+     *          :next  =,
+     *          doc2 : { match = true }
+     *       }
+     *    }
+     * </code>
+     */
+    @Test
+    public void deleteOneOfTheDocuments() {
+        final String N0 = KEYS[0];
+        final String DOC1 = "doc1";
+        final String DOC2 = "doc2";
+        final String PATH1 = "/" + DOC1;
+        final String PATH2 = "/" + DOC2;
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        store.update(index, PATH1, EMPTY_KEY_SET, newHashSet(N0));
+        store.update(index, PATH2, EMPTY_KEY_SET, newHashSet(N0));
+
+        // we trust the store at this point and skip a double-check. Let's move
+        // to Stage 2!
+
+        store.update(index, PATH1, newHashSet(N0), EMPTY_KEY_SET);
+
+        assertTrue(index.hasChildNode(START));
+        assertTrue(index.hasChildNode(N0));
+        assertEquals(":start should still point to N0", N0, index.getChildNode(START).getString(NEXT));
+        assertTrue("n0 should point nowhere", Strings.isNullOrEmpty(index.getChildNode(N0).getString(NEXT)));
+
+        assertFalse(index.getChildNode(N0).hasChildNode(DOC1));
+        assertTrue(index.getChildNode(N0).hasChildNode(DOC2));
+        assertTrue(index.getChildNode(N0).getChildNode(DOC2).getBoolean("match"));
+    }
+
+    /**
+     * test when the only document is deleted from an indexed key but there're
+     * still some keys left in the index
+     * 
+     * <p>
+     * <i>it relies on the functionality of the store.update() for creating the
+     * index</i>
+     * </p>
+     * 
+     * <code>
+     *    Stage 1
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n1 },
+     *       n0 : {
+     *          :next = ,
+     *          content : {
+     *             doc0 : { match = true }
+     *          }
+     *       },
+     *       n1 : {
+     *          :next = n2,
+     *          content : {
+     *             doc1 : { match = true }
+     *          }
+     *       }
+     *       n2 : {
+     *          :next = n0,
+     *          content : {
+     *             doc2 : { match = true }
+     *          }
+     *       }
+     *    }
+     *    
+     *    Stage 2
+     *    =======
+     *    
+     *    :index : {
+     *       :start : { :next = n1 },
+     *       n0 : {
+     *          :next = ,
+     *          content : {
+     *             doc0 : { match = true }
+     *          }
+     *       },
+     *       n1 : {
+     *          :next = n0,
+     *          content : {
+     *             doc1 : { match = true }
+     *          }
+     *       }
+     *    }
+     *    
+     * </code>
+     */
+    @Test
+    public void deleteTheOnlyDocumentInMultiKeysIndex() {
+        final String PATH0 = "/content/doc0";
+        final String PATH1 = "/content/doc1";
+        final String PATH2 = "/content/doc2";
+        final String N0 = KEYS[2];
+        final String N1 = KEYS[0];
+        final String N2 = KEYS[1];
+
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        IndexStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+
+        // Stage 1
+        store.update(index, PATH0, EMPTY_KEY_SET, newHashSet(N0));
+        store.update(index, PATH1, EMPTY_KEY_SET, newHashSet(N1));
+        store.update(index, PATH2, EMPTY_KEY_SET, newHashSet(N2));
+
+        // as we trust the store we skip the check and goes straight to Stage 2.
+
+        // Stage 2
+        store.update(index, PATH2, newHashSet(N2), EMPTY_KEY_SET);
+
+        // checking key nodes
+        assertTrue(index.hasChildNode(START));
+        assertTrue(index.hasChildNode(N0));
+        assertTrue(index.hasChildNode(N1));
+        assertFalse(index.hasChildNode(N2));
+
+        // checking pointers
+        assertEquals(N1, index.getChildNode(START).getString(NEXT));
+        assertEquals(N0, index.getChildNode(N1).getString(NEXT));
+        assertTrue(Strings.isNullOrEmpty(index.getChildNode(N0).getString(NEXT)));
+
+        // checking sub-nodes
+        String[] subNodes = Iterables.toArray(PathUtils.elements(PATH0), String.class);
+        assertTrue(index.getChildNode(N0).hasChildNode(subNodes[0]));
+        assertTrue(index.getChildNode(N0).getChildNode(subNodes[0]).hasChildNode(subNodes[1]));
+        assertTrue(index.getChildNode(N0).getChildNode(subNodes[0]).getChildNode(subNodes[1]).getBoolean("match"));
+
+        subNodes = Iterables.toArray(PathUtils.elements(PATH1), String.class);
+        assertTrue(index.getChildNode(N1).hasChildNode(subNodes[0]));
+        assertTrue(index.getChildNode(N1).getChildNode(subNodes[0]).hasChildNode(subNodes[1]));
+        assertTrue(index.getChildNode(N1).getChildNode(subNodes[0]).getChildNode(subNodes[1]).getBoolean("match"));
+    }
+}

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1574837&r1=1574836&r2=1574837&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java Thu Mar  6 10:26:06 2014
@@ -30,6 +30,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.commit.JcrConflictHandler;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.OrderedPropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider;
 import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider;
@@ -79,6 +80,8 @@ public class Jcr {
 
         with(new PropertyIndexProvider());
         with(new NodeTypeIndexProvider());
+        
+        with(new OrderedPropertyIndexEditorProvider());
     }
 
     public Jcr() {

Modified: jackrabbit/oak/trunk/oak-run/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/pom.xml?rev=1574837&r1=1574836&r2=1574837&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-run/pom.xml Thu Mar  6 10:26:06 2014
@@ -186,12 +186,19 @@
       <groupId>org.apache.jclouds.provider</groupId>
       <artifactId>aws-s3</artifactId>
     </dependency>
+    
+    <!-- Findbugs annotations -->
+    <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+    </dependency>
+    
     <!-- Test dependencies -->
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
+    
   </dependencies>
-
 </project>

Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java?rev=1574837&r1=1574836&r2=1574837&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java Thu Mar  6 10:26:06 2014
@@ -97,6 +97,13 @@ public class BenchmarkRunner {
                         base.value(options), 256, cacheSize, mmap.value(options))
         };
         Benchmark[] allBenchmarks = new Benchmark[] {
+            new OrderedIndexQueryOrderedIndexTest(),
+            new OrderedIndexQueryStandardIndexTest(),
+            new OrderedIndexQueryNoIndexTest(),
+            new OrderedIndexInsertOrderedPropertyTest(),
+            new OrderedIndexInsertStandardPropertyTest(),
+            new OrderedIndexInsertNoIndexTest(),
+            new OrderByQueryTest(),
             new LoginTest(),
             new LoginLogoutTest(),
             new NamespaceTest(),

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderByQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderByQueryTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderByQueryTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderByQueryTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,89 @@
+/*
+ * 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.benchmark;
+
+import java.util.Random;
+import java.util.UUID;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+
+/**
+ * This benchmark measures the read performance of child nodes using
+ * an ORDER BY query.
+ * <p>
+ * This is related to OAK-1263.
+ * 
+ */
+public class OrderByQueryTest extends AbstractTest {
+
+	private static final String NT = "oak:unstructured";
+
+	private static final String ROOT_NODE_NAME = "test" + TEST_ID;
+	private static final int NUM_NODES = 10000;
+	private static final String PROPERTY_NAME = "testProperty";
+	private static final Random random = new Random(); // doesn't have to be very secure, just some randomness
+
+    @Override
+    protected void beforeSuite() throws Exception {
+        Session session = loginWriter();
+        Node rootNode = session.getRootNode();
+        if (rootNode.hasNode(ROOT_NODE_NAME)) {
+            Node root = rootNode.getNode(ROOT_NODE_NAME);
+            root.remove();
+        }
+        rootNode = session.getRootNode().addNode(ROOT_NODE_NAME, NT);
+        
+        for (int i = 0; i < NUM_NODES; i++) {
+        	if (i%1000==0) {
+        		session.save();
+        	}
+            Node newNode = rootNode.addNode(UUID.randomUUID().toString(), NT);
+            newNode.setProperty(PROPERTY_NAME, random.nextLong());
+        }
+        session.save();
+    }
+
+    @Override
+    public void runTest() throws Exception {
+        final Session session = loginWriter();
+        try {
+            // run the query
+            final QueryManager qm = session.getWorkspace().getQueryManager();
+
+            final Query q =
+                    qm.createQuery("SELECT * FROM [oak:unstructured] AS s WHERE "
+                    		+ "ISDESCENDANTNODE(s, [/"+ROOT_NODE_NAME+"/]) ORDER BY s."+PROPERTY_NAME+"]",
+                    		Query.JCR_SQL2);
+            final QueryResult res = q.execute();
+
+            final NodeIterator nit = res.getNodes();
+//            while(nit.hasNext()) {
+//            	Node node = nit.nextNode();
+////            	System.out.println("node: "+node.getPath()+", prop="+node.getProperty(PROPERTY_NAME).getLong());
+//            }
+        } catch (RepositoryException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexBaseTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexBaseTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexBaseTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexBaseTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,112 @@
+/*
+ * 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.benchmark;
+
+import java.util.UUID;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.oak.benchmark.util.OakIndexUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.property.OrderedPropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+
+/**
+ *
+ */
+public abstract class OrderedIndexBaseTest extends AbstractTest {
+    /**
+     * the number of nodes created per iteration
+     */
+    static final int NODES_PER_ITERATION = Integer.parseInt(System.getProperty("nodesPerIteration", "100"));
+    
+    /**
+     * number of nodes that has to be added before performing the actual test
+     */
+    static final int PRE_ADDED_NODES = Integer.parseInt(System.getProperty("preAddedNodes", "0"));
+
+    /**
+    * type of the created node
+    */
+   static final String NODE_TYPE = NodeTypeConstants.NT_OAK_UNSTRUCTURED;
+      
+   /**
+    * property that will be indexed
+    */
+   static final String INDEXED_PROPERTY = "indexedProperty";
+   
+   /**
+    * node name below which creating the test data
+    */
+   final String DUMP_NODE = this.getClass().getSimpleName() + TEST_ID;
+
+   /**
+    * session used for operations throughout the test
+    */
+   Session session;
+   
+   /**
+    * node under which all the test data will be filled in
+    */
+   Node dump;
+      
+   void insertRandomNodes(int numberOfNodes){
+      try{
+         for(int i=0; i<numberOfNodes; i++){
+            String uuid = UUID.randomUUID().toString();
+            dump.addNode(uuid, NODE_TYPE).setProperty(INDEXED_PROPERTY, uuid);
+            session.save();            
+         }
+      } catch (RepositoryException e){
+         throw new RuntimeException(e);
+      }      
+   }
+
+   /**
+    * override when needed to define an index
+    */
+   void defineIndex() throws Exception{
+   }
+   
+   Node defineStandardPropertyIndex(Session session) throws Exception {
+       Node index = new OakIndexUtils.PropertyIndex().property(INDEXED_PROPERTY).create(session);
+       if(index == null) {
+           throw new RuntimeException("Error while creating the index definition. index node is null.");
+       }
+       if(!PropertyIndexEditorProvider.TYPE.equals(index.getProperty(IndexConstants.TYPE_PROPERTY_NAME).getString())) {
+           throw new RuntimeException("The type of the index does not match the expected");
+       }
+       session.save();
+       return index;
+   }
+   
+   Node defineOrderedPropertyIndex(Session session) throws Exception {
+       Node index = new OakIndexUtils.PropertyIndex().property(INDEXED_PROPERTY).create(session,OrderedPropertyIndexEditorProvider.TYPE);
+       if(index == null) {
+           throw new RuntimeException("Error while creating the index definition. index node is null.");
+       }
+       if(!OrderedPropertyIndexEditorProvider.TYPE.equals(index.getProperty(IndexConstants.TYPE_PROPERTY_NAME).getString())) {
+           throw new RuntimeException("The index type does not match the expected");
+       }
+       session.save();
+       return index;
+   }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertBaseTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertBaseTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertBaseTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertBaseTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,52 @@
+/*
+ * 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.benchmark;
+
+/**
+ * intermediate class for the testing of Inserts of nodes.
+ */
+public abstract class OrderedIndexInsertBaseTest extends OrderedIndexBaseTest {
+    @Override
+    protected void beforeTest() throws Exception {
+       session = loginWriter();
+
+       //initiate the place for writing child nodes
+       dump = session.getRootNode().addNode(DUMP_NODE,NODE_TYPE);
+       session.save();
+       
+       defineIndex();
+       
+       //pre-adding nodes
+       insertRandomNodes(PRE_ADDED_NODES);
+    }
+
+    @Override
+    protected void afterTest() throws Exception {
+       //clean-up our mess
+       dump.remove();
+       session.save();
+       session.logout();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jackrabbit.oak.benchmark.AbstractTest#runTest()
+     */
+    @Override
+    protected void runTest() throws Exception {
+       insertRandomNodes(NODES_PER_ITERATION);
+    }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertNoIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertNoIndexTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertNoIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertNoIndexTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,30 @@
+/*
+ * 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.benchmark;
+
+
+public class OrderedIndexInsertNoIndexTest extends OrderedIndexInsertBaseTest {
+   /*
+    * this class is empty extending a base only because during benchmark testing
+    * it was found that an extended class had an overhead of 4-6ms even if it was 
+    * not doing anything. Like this one.
+    * 
+    * So in order to have consistent numbers to compare here's this empty extension.
+    * 
+    * (or at least as much consistent as possible).
+    */
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertOrderedPropertyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertOrderedPropertyTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertOrderedPropertyTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertOrderedPropertyTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,39 @@
+/*
+ * 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.benchmark;
+
+import javax.jcr.Node;
+
+/**
+ *
+ */
+public class OrderedIndexInsertOrderedPropertyTest extends OrderedIndexInsertBaseTest {
+   private Node index = null;
+   
+   @Override
+   void defineIndex() throws Exception{
+       index = defineOrderedPropertyIndex(session);
+   }
+
+   @Override
+   protected void afterTest() throws Exception {
+      //deleting the index. no need for session.save(); as it will be run by the super.afterTest();
+      index.remove();
+      super.afterTest();
+   }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertStandardPropertyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertStandardPropertyTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertStandardPropertyTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexInsertStandardPropertyTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,39 @@
+/*
+ * 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.benchmark;
+
+import javax.jcr.Node;
+
+/**
+ *
+ */
+public class OrderedIndexInsertStandardPropertyTest extends OrderedIndexInsertBaseTest {
+   private Node index = null;
+   
+   @Override
+   void defineIndex() throws Exception {
+       index = defineStandardPropertyIndex(session);   
+   }
+
+   @Override
+   protected void afterTest() throws Exception {
+      //deleting the index. no need for session.save(); as it will be run by the super.afterTest();
+      index.remove();
+      super.afterTest();
+   }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryBaseTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryBaseTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryBaseTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryBaseTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,80 @@
+/*
+ * 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.benchmark;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+
+/**
+ * Benchmark the query performance of an ORDER BY clause when No index are involved
+ */
+public abstract class OrderedIndexQueryBaseTest extends OrderedIndexBaseTest {
+    Node index;
+    
+    /**
+     * query to execute with the ORDER BY statement
+     */
+    public static final String QUERY_WITH_ORDER = String.format(
+        "SELECT * FROM [%s] WHERE %s IS NOT NULL ORDER BY %s", NODE_TYPE, INDEXED_PROPERTY, INDEXED_PROPERTY);
+    
+    /**
+     * constant used to identify how many nodes will be fetched after the query execution
+     */
+    public static final int FETCH_NODES = 100;
+    
+    /**
+     * query to execute WITHOUT the ORDER BY clause
+     */
+    public static final String QUERY_WITHOUT_ORDER = String.format(
+        "SELECT * FROM [%s] WHERE %s IS NOT NULL", NODE_TYPE, INDEXED_PROPERTY);
+
+    @Override
+    protected void beforeSuite() throws Exception {
+        session = loginWriter();
+        dump = session.getRootNode().addNode(DUMP_NODE, NODE_TYPE);
+        session.save();
+        defineIndex();
+        insertRandomNodes(PRE_ADDED_NODES);
+    }
+
+    @Override
+    protected void afterSuite() throws Exception {
+        dump.remove();
+        if(index!=null) {
+            index.remove();
+        }
+        session.save();
+        session.logout();
+    }
+
+    @Override
+    protected void runTest() throws Exception {
+        QueryManager qm = session.getWorkspace().getQueryManager();
+        Query q = qm.createQuery(getQuery(), Query.JCR_SQL2);
+        QueryResult r = q.execute();
+        NodeIterator nodes = r.getNodes();
+        int counter = 0;
+        while(nodes.hasNext() && counter++<FETCH_NODES) {
+            nodes.next();
+        }
+    }
+    
+    abstract String getQuery();
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryNoIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryNoIndexTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryNoIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryNoIndexTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,29 @@
+/*
+ * 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.benchmark;
+
+
+/**
+ * Benchmark the query performance of an ORDER BY clause when No index are involved
+ */
+public class OrderedIndexQueryNoIndexTest extends OrderedIndexQueryBaseTest {
+
+    @Override
+    String getQuery() {
+        return QUERY_WITH_ORDER;
+    }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryOrderedIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryOrderedIndexTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryOrderedIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryOrderedIndexTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,34 @@
+/*
+ * 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.benchmark;
+
+
+/**
+ * Benchmark the query performance of an ORDER BY clause when No index are involved
+ */
+public class OrderedIndexQueryOrderedIndexTest extends OrderedIndexQueryBaseTest {
+
+    @Override
+    void defineIndex() throws Exception {
+        index = defineOrderedPropertyIndex(session);
+    }
+
+    @Override
+    String getQuery() {
+        return QUERY_WITHOUT_ORDER;
+    }
+}

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryStandardIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryStandardIndexTest.java?rev=1574837&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryStandardIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/OrderedIndexQueryStandardIndexTest.java Thu Mar  6 10:26:06 2014
@@ -0,0 +1,34 @@
+/*
+ * 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.benchmark;
+
+
+/**
+ * Benchmark the query performance of an ORDER BY clause when No index are involved
+ */
+public class OrderedIndexQueryStandardIndexTest extends OrderedIndexQueryBaseTest {
+
+    @Override
+    void defineIndex() throws Exception {
+        index = defineStandardPropertyIndex(session);
+    }
+
+    @Override
+    String getQuery() {
+        return QUERY_WITH_ORDER;
+    }
+}

Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/OakIndexUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/OakIndexUtils.java?rev=1574837&r1=1574836&r2=1574837&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/OakIndexUtils.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/util/OakIndexUtils.java Thu Mar  6 10:26:06 2014
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.benchm
 
 import java.util.Arrays;
 
+import javax.annotation.Nullable;
 import javax.jcr.Node;
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
@@ -87,16 +88,22 @@ public class OakIndexUtils {
          * definition matches. If no such index exists, a new one is created.
          * 
          * @param session the session to use for creating the index
+         * @return the index node
          * @throws RepositoryException if writing to the repository failed, the
          *             index definition is incorrect, or if such an index exists
          *             but is not compatible with this definition (for example,
          *             a different property is indexed)
          */
-        public void create(Session session) throws RepositoryException {
-            if (!session.getWorkspace().getNodeTypeManager().hasNodeType(
+        public @Nullable Node create(Session session) throws RepositoryException {
+           return create(session,PropertyIndexEditorProvider.TYPE);
+        }
+        
+        public @Nullable Node create(Session session,String indexType) throws RepositoryException {
+           Node index = null;
+           if (!session.getWorkspace().getNodeTypeManager().hasNodeType(
                         "oak:QueryIndexDefinition")) {
                 // not an Oak repository
-                return;
+                return index;
             }
             if (session.hasPendingChanges()) {
                 throw new RepositoryException("The session has pending changes");
@@ -117,7 +124,7 @@ public class OakIndexUtils {
                 }
             }
             Node root = session.getRootNode();
-            Node indexDef;
+            Node indexDef = null;
             if (!root.hasNode(IndexConstants.INDEX_DEFINITIONS_NAME)) {
                 indexDef = root.addNode(IndexConstants.INDEX_DEFINITIONS_NAME, 
                         JcrConstants.NT_UNSTRUCTURED);
@@ -125,7 +132,7 @@ public class OakIndexUtils {
             } else {
                 indexDef = root.getNode(IndexConstants.INDEX_DEFINITIONS_NAME);
             }
-            Node index;
+
             if (indexDef.hasNode(indexName)) {
                 // verify the index matches
                 index = indexDef.getNode(indexName);
@@ -138,7 +145,7 @@ public class OakIndexUtils {
                 }
                 String type = index.getProperty(
                         IndexConstants.TYPE_PROPERTY_NAME).getString();
-                if (!type.equals(PropertyIndexEditorProvider.TYPE)) {
+                if (!type.equals(indexType)) {
                     throw new RepositoryException(
                             "Index already exists, but is of type " + type);
                 }
@@ -171,11 +178,10 @@ public class OakIndexUtils {
                             "Index already exists, but without node type restriction");
                 }
                 // matches
-                return;
+                return index;
             }
             index = indexDef.addNode(indexName, IndexConstants.INDEX_DEFINITIONS_NODE_TYPE);
-            index.setProperty(IndexConstants.TYPE_PROPERTY_NAME, 
-                    PropertyIndexEditorProvider.TYPE);
+            index.setProperty(IndexConstants.TYPE_PROPERTY_NAME, indexType);
             index.setProperty(IndexConstants.REINDEX_PROPERTY_NAME, 
                     true);
             index.setProperty(IndexConstants.PROPERTY_NAMES, 
@@ -185,8 +191,8 @@ public class OakIndexUtils {
                         nodeTypeNames);
             }
             session.save();
+            return index;
         }
-        
     }
 
-}
+}
\ No newline at end of file



Mime
View raw message