From 6bb2209f9e5aac1dcb1878a25958353f46b19e01 Mon Sep 17 00:00:00 2001
From: Davide Giannella <giannella.davide@gmail.com>
Date: Thu, 29 May 2014 14:49:18 +0200
Subject: [PATCH] OAK-1570 merge with latest trunk and minor fixes

---
 .../oak/plugins/index/property/OrderedIndex.java   |   38 +
 .../strategy/ContentMirrorStoreStrategy.java       |    5 +-
 .../OrderedContentMirrorStoreStrategy.java         |  485 ++--
 .../BasicOrderedPropertyIndexQueryTest.java        |    6 +-
 .../OrderedPropertyIndexDescendingQueryTest.java   |   39 +-
 .../property/OrderedPropertyIndexQueryTest.java    |   50 +-
 .../OrderedContentMirrorStorageStrategyTest.java   | 2348 ++++++++++++++++++--
 .../oak/jcr/OrderedIndexConcurrentClusterIT.java   |   22 +-
 8 files changed, 2652 insertions(+), 341 deletions(-)

diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedIndex.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedIndex.java
index aa7caa9..ba92511 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedIndex.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedIndex.java
@@ -92,6 +92,14 @@ public interface OrderedIndex {
             return DESC.equals(fromIndexMeta(indexMeta));
         }
         
+        public boolean isAscending() {
+            return ASC.equals(this);
+        }
+        
+        public boolean isDescending() {
+            return DESC.equals(this);
+        }
+
         /**
          * convenience method that tells if the provided index definition is ascending
          * 
@@ -116,4 +124,34 @@ public interface OrderedIndex {
      * the default direction for sorting the index
      */
     OrderDirection DEFAULT_DIRECTION = OrderDirection.ASC;
+    
+    /**
+     * defines the default distribution of items across the skip list. It's with a factor of 10%
+     * having therefore
+     * 
+     * <dl>
+     *  <dt>lane 0:</dt> <dd>100.0% (the base linked list)</dd>
+     *  <dt>lane 1:</dt> <dd>10.0%</dd>
+     *  <dt>lane 2:</dt> <dd>1.0%</dd>
+     *  <dt>lane 3:</dt> <dd>0.1%</dd>
+     * </dl>
+     */
+    double DEFAULT_PROBABILITY = 0.1;
+    
+    /**
+     * the number of lanes used in the SkipList 
+     */
+    int LANES = 4;
+    
+    /**
+     * Convenience Predicate that will force the implementor to expose what we're searching for
+     *
+     * @param <T>
+     */
+    interface Predicate<T> extends com.google.common.base.Predicate<T> {
+        /**
+         * @return the string we're searching for during this predicate
+         */
+        String getSearchFor();
+    }
 }
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
index 4a0a6ae..2ddd097 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
@@ -100,7 +100,7 @@ public class ContentMirrorStoreStrategy implements IndexStoreStrategy {
             }
 
             // Prune all index nodes that are no longer needed
-            prune(index, builders);
+            prune(index, builders, key);
         }
     }
 
@@ -431,8 +431,9 @@ public class ContentMirrorStoreStrategy implements IndexStoreStrategy {
      *            the current index
      * @param builders
      *            list of nodes to prune
+     * @param key the key of the index we're processing
      */
-    void prune(final NodeBuilder index, final Deque<NodeBuilder> builders) {
+    void prune(final NodeBuilder index, final Deque<NodeBuilder> builders, final String key) {
         for (NodeBuilder node : builders) {
             if (node.getBoolean("match") || node.getChildNodeCount(1) > 0) {
                 return;
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
index 92d4655..0fd121c 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStoreStrategy.java
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Random;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -32,6 +33,7 @@ import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex;
 import org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
+import org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.Predicate;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
@@ -42,8 +44,9 @@ import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 /**
  * Same as for {@link ContentMirrorStoreStrategy} but the order of the keys is kept by using the
@@ -60,6 +63,15 @@ import com.google.common.base.Strings;
  * </code>
  */
 public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrategy {
+    /**
+     * convenience property for initialising an empty multi-value :next
+     */
+    public static final Iterable<String> EMPTY_NEXT = ImmutableList.of("", "", "", "");
+    
+    /**
+     * convenience property that represent an empty :next as array
+     */
+    public static final String[] EMPTY_NEXT_ARRAY = Iterables.toArray(EMPTY_NEXT, String.class);
 
     /**
      * the property linking to the next node
@@ -75,11 +87,12 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
      * a NodeState used for easy creating of an empty :start
      */
     public static final NodeState EMPTY_START_NODE = EmptyNodeState.EMPTY_NODE.builder()
-                                                                              .setProperty(NEXT, "")
-                                                                              .getNodeState();
+        .setProperty(NEXT, EMPTY_NEXT, Type.STRINGS).getNodeState();
 
     private static final Logger LOG = LoggerFactory.getLogger(OrderedContentMirrorStoreStrategy.class);
     
+    private static final Random RND = new Random(System.currentTimeMillis());
+    
     /**
      * the direction of the index.
      */
@@ -96,80 +109,73 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
     
     @Override
     NodeBuilder fetchKeyNode(@Nonnull NodeBuilder index, @Nonnull String key) {
-        NodeBuilder localkey = null;
+        // this is where the actual adding and maintenance of index's keys happen
+        NodeBuilder node = null;
         NodeBuilder start = index.child(START);
-
-        // identifying the right place for insert
-        String n = start.getString(NEXT);
-        if (Strings.isNullOrEmpty(n)) {
-            // new/empty index
-            localkey = index.child(key);
-            localkey.setProperty(NEXT, "");
-            start.setProperty(NEXT, key);
-        } else {
-            // specific use-case where the item has to be added as first of the list
-            String nextKey = n;
-            Iterable<? extends ChildNodeEntry> children = getChildNodeEntries(index.getNodeState(),
-                                                                              true);
-            for (ChildNodeEntry child : children) {
-                nextKey = child.getNodeState().getString(NEXT);
-                if (Strings.isNullOrEmpty(nextKey)) {
-                    // we're at the last element, therefore our 'key' has to be appended
-                    index.getChildNode(child.getName()).setProperty(NEXT, key);
-                    localkey = index.child(key);
-                    localkey.setProperty(NEXT, "");
+        Predicate<ChildNodeEntry> condition = direction.isAscending() 
+            ? new PredicateGreaterThan(key, true)
+            : new PredicateLessThan(key, true);
+        ChildNodeEntry[] walked = new ChildNodeEntry[OrderedIndex.LANES];
+        
+        if (Strings.isNullOrEmpty(getPropertyNext(start))) {
+            // it means we're in an empty/new index. Setting properly the :start's :next
+            setPropertyNext(start, EMPTY_NEXT_ARRAY);
+        }
+        
+        // we use the seek for seeking the right spot. The walkedLanes will have all our
+        // predecessors
+        ChildNodeEntry entry = seek(index.getNodeState(), condition, walked);
+        if (entry != null && entry.getName().equals(key)) {
+            // it's an existing node. We should not need to update anything around pointers
+            node = index.getChildNode(key);
         } else {
-                    if (isInsertHere(key, nextKey)) {
-                        index.getChildNode(child.getName()).setProperty(NEXT, key);
-                        localkey = index.child(key);
-                        localkey.setProperty(NEXT, nextKey);
-                        break;
-                    }
-                }
+            // the entry does not exits yet
+            node = index.child(key);
+            // it's a brand new node. let's start setting an empty next
+            setPropertyNext(node, EMPTY_NEXT_ARRAY);
+            int lane = getLane();
+            String next;
+            NodeBuilder predecessor;
+            for (int l = lane; l >= 0; l--) {
+                // let's update the predecessors starting from the coin-flip lane
+                predecessor = index.getChildNode(walked[l].getName());
+                next = getPropertyNext(predecessor, l);
+                setPropertyNext(predecessor, key, l);
+                setPropertyNext(node, next, l);
             }
         }
-
-        return localkey;
-    }
-
-    /**
-     * tells whether or not the is right to insert here a new item.
-     * 
-     * @param newItemKey the new item key to be added
-     * @param existingItemKey the 'here' of the existing index
-     * @return true for green light on insert false otherwise.
-     */
-    private boolean isInsertHere(@Nonnull String newItemKey, @Nonnull String existingItemKey) {
-        if (OrderDirection.ASC.equals(direction)) {
-            return newItemKey.compareTo(existingItemKey) < 0;
-        } else {
-            return newItemKey.compareTo(existingItemKey) > 0;
-        }
+        return node;
     }
                                         
     @Override
-    void prune(final NodeBuilder index, final Deque<NodeBuilder> builders) {
+    void prune(final NodeBuilder index, final Deque<NodeBuilder> builders, final String key) {
         for (NodeBuilder node : builders) {
             if (node.hasProperty("match") || node.getChildNodeCount(1) > 0) {
                 return;
             } else if (node.exists()) {
                 if (node.hasProperty(NEXT)) {
-                    // it's an index key and we have to relink the list
-                    // (1) find the previous element
-                    ChildNodeEntry previous = findPrevious(
-                            index.getNodeState(), node.getNodeState());
-                    if (previous == null) {
-                        LOG.debug("previous not found. Already deleted in the meanwhile. Skipping re-link");
-                    } else {
-                        LOG.debug("previous: {}", previous);
-                        // (2) find the next element
-                        String next = node.getString(NEXT);
-                        if (next == null) {
-                            next = "";
-                        }
-                        // (3) re-link the previous to the next
-                        index.getChildNode(previous.getName()).setProperty(NEXT, next);
-                    }
+                    ChildNodeEntry[] walkedLanes = new ChildNodeEntry[OrderedIndex.LANES];
+                    ChildNodeEntry entry;
+                    String lane0Next, prevNext, currNext;
+                    
+                    // for as long as we have the an entry and we didn't update the lane0 we have
+                    // to keep searching and update
+                    do {
+                        entry = seek(index.getNodeState(),
+                            new PredicateEquals(key),
+                            walkedLanes
+                            );
+                        lane0Next = getPropertyNext(walkedLanes[0]);
+                        for (int lane = walkedLanes.length - 1; lane >= 0; lane--) {
+                            prevNext = getPropertyNext(walkedLanes[lane], lane);
+                            if (key.equals(prevNext)) {
+                                // if it's actually pointing to us let's deal with it
+                                currNext = getPropertyNext(node, lane);
+                                setPropertyNext(index.getChildNode(walkedLanes[lane].getName()),
+                                    currNext, lane);
+                            }
+                        }
+                    } while (entry != null && !key.equals(lane0Next));
                 }
                 node.remove();
             }
@@ -177,43 +183,6 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
     }
 
     /**
-     * find the previous item (ChildNodeEntry) in the index given the provided NodeState for
-     * comparison
-     * 
-     * in an index sorted in ascending manner where we have @{code [1, 2, 3, 4, 5]} if we ask for 
-     * a previous given 4 it will be 3. previous(4)=3.
-     * 
-     * in an index sorted in descending manner where we have @{code [5, 4, 3, 2, 1]} if we as for
-     * a previous given 4 it will be 5. previous(4)=5.
-     * 
-     * @param index the index we want to look into ({@code :index})
-     * @param node the node we want to compare
-     * @return the previous item or null if not found.
-     */
-    @Nullable
-    ChildNodeEntry findPrevious(@Nonnull final NodeState index, @Nonnull final NodeState node) {
-        ChildNodeEntry previous = null;
-        ChildNodeEntry current = null;
-        boolean found = false;
-        Iterator<? extends ChildNodeEntry> it = getChildNodeEntries(index, true).iterator();
-
-        while (!found && it.hasNext()) {
-            current = it.next();
-            if (previous == null) {
-                // first iteration
-                previous = current;
-            } else {
-                found = node.equals(current.getNodeState());
-                if (!found) {
-                    previous = current;
-                }
-            }
-        }
-
-        return found ? previous : null;
-    }
-
-    /**
      * retrieve an Iterable for going through the index in the right order without the :start node
      * 
      * @param index the root of the index (:index)
@@ -239,7 +208,8 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
         Iterable<? extends ChildNodeEntry> cne = null;
         final NodeState start = index.getChildNode(START);
 
-        if ((!start.exists() || Strings.isNullOrEmpty(start.getString(NEXT))) && !includeStart) {
+        String startNext = getPropertyNext(start); 
+        if ((!start.exists() || Strings.isNullOrEmpty(startNext)) && !includeStart) {
             // if the property is not there or is empty it means we're empty
             cne = Collections.emptyList();
         } else {
@@ -290,8 +260,14 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
                 firstValueableItem = seek(index,
                     new PredicateGreaterThan(pr.first.getValue(Type.STRING), pr.firstIncluding));
                 if (firstValueableItem != null) {
+                    if (direction.isAscending()) {
                         childrenIterable = new SeekedIterable(index, firstValueableItem);
                         it = new QueryResultsWrapper(filter, indexName, childrenIterable);
+                    } else {
+                        it = new QueryResultsWrapper(filter, indexName, new BetweenIterable(index,
+                            firstValueableItem, pr.first.getValue(Type.STRING), pr.firstIncluding,
+                            direction));
+                    }
                 }
             } else {
                 String first, last;
@@ -341,9 +317,14 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
             
             Iterable<String> it = Collections.emptyList();
             if (firstValueableItem != null) {
+                if (direction.isAscending()) {
+                    it = new QueryResultsWrapper(filter, indexName, new BetweenIterable(index,
+                        firstValueableItem, searchfor, include, direction));
+                } else {
                     it = new QueryResultsWrapper(filter, indexName, new SeekedIterable(index,
                         firstValueableItem));
                 }
+            }
             return it;
         } else {
             // property is not null. AKA "open query"
@@ -356,7 +337,7 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
         return value.replaceAll("%3A", ":");
     }
     
-    private static final class OrderedChildNodeEntry extends AbstractChildNodeEntry {
+    static class OrderedChildNodeEntry extends AbstractChildNodeEntry {
         private final String name;
         private final NodeState state;
 
@@ -447,6 +428,11 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
                         
                         return b;
                     }
+
+                    @Override
+                    public String getSearchFor() {
+                        throw new UnsupportedOperationException();
+                    }
                 };
 
                 CountingNodeVisitor v;
@@ -497,6 +483,11 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
                         
                         return b;
                     }
+
+                    @Override
+                    public String getSearchFor() {
+                        throw new UnsupportedOperationException();
+                    }
                 };
                 
                 CountingNodeVisitor v;
@@ -558,9 +549,9 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
     private static class FullIterator implements Iterator<ChildNodeEntry> {
         private boolean includeStart;
         private NodeState start;
-        private NodeState current;
+        NodeState current;
         private NodeState index;
-        private String currentName;
+        String currentName;
 
         public FullIterator(NodeState index, NodeState start, boolean includeStart,
                             NodeState current) {
@@ -573,7 +564,7 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
         @Override
         public boolean hasNext() {
             return (includeStart && start.equals(current))
-                   || (!includeStart && !Strings.isNullOrEmpty(current.getString(NEXT)));
+                   || (!includeStart && !Strings.isNullOrEmpty(getPropertyNext(current)));
         }
 
         @Override
@@ -585,7 +576,7 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
                 includeStart = false;
             } else {
                 if (hasNext()) {
-                    currentName = current.getString(NEXT);
+                    currentName = getPropertyNext(current);
                     current = index.getChildNode(currentName);
                     entry = new OrderedChildNodeEntry(currentName, current);
                 } else {
@@ -670,6 +661,8 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
             if (firstReturned) {
                 return super.next();
             } else {
+                currentName = first.getName();
+                current = first.getNodeState();
                 firstReturned = true;
                 return first;
             }
@@ -694,26 +687,114 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
     }
 
     /**
-     * seek for an element in the index given the provided Predicate
+     * see {@link #seek(NodeState, Predicate<ChildNodeEntry>, ChildNodeEntry[])} passing null as
+     * last argument
+     */
+    ChildNodeEntry seek(@Nonnull NodeState index,
+                                      @Nonnull Predicate<ChildNodeEntry> condition) {
+        return seek(index, condition, null);
+    }
+    
+    /**
+     * seek for an element in the index given the provided Predicate. If {@code walkedLanes} won't
+     * be null it will have on the way out the last elements of each lane walked through during the
+     * seek.
      * 
      * @param index the index content node {@code :index}
      * @param condition the predicate to evaluate
+     * @param walkedLanes if not null will contain the last element of the walked lanes with each
+     *            lane represented by the corresponding position in the array. <b>You have</b> to
+     *            pass in an array already sized as {@link OrderedIndex#LANES} or an
+     *            {@link IllegalArgumentException} will be raised
      * @return the entry or null if not found
      */
-    static ChildNodeEntry seek(@Nonnull NodeState index,
-                                      @Nonnull Predicate<ChildNodeEntry> condition) {
-        
-        // TODO the FullIterable will have to be replaced with something else once we'll have the
-        // Skip part of the list implemented.
-        Iterable<ChildNodeEntry> children = new FullIterable(index, false);
-        ChildNodeEntry entry = null;
-        for (ChildNodeEntry child : children) {
-            if (condition.apply(child)) {
-                entry = child;
-                break;
+    ChildNodeEntry seek(@Nonnull final NodeState index,
+                               @Nonnull final Predicate<ChildNodeEntry> condition,
+                               @Nullable final ChildNodeEntry[] walkedLanes) {
+        boolean keepWalked = false;
+        String searchfor = condition.getSearchFor();
+        LOG.debug("seek() - Searching for: {}", condition.getSearchFor());        
+        Predicate<ChildNodeEntry> walkingPredicate = direction.isAscending() 
+                                                             ? new PredicateLessThan(searchfor, true)
+                                                             : new PredicateGreaterThan(searchfor, true);
+        // we always begin with :start
+        ChildNodeEntry current = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        ChildNodeEntry found = null;
+        
+        if (walkedLanes != null) {
+            if (walkedLanes.length != OrderedIndex.LANES) {
+                throw new IllegalArgumentException(String.format(
+                    "Wrong size for keeping track of the Walked Lanes. Expected %d but was %d",
+                    OrderedIndex.LANES, walkedLanes.length));
+            }
+            // ensuring the right data
+            for (int i = 0; i < walkedLanes.length; i++) {
+                walkedLanes[i] = current;
+            }
+            keepWalked = true;
+        }
+
+        int lane;
+        boolean stillLaning;
+        String nextkey; 
+        ChildNodeEntry next;
+
+        if ((direction.isAscending() && condition instanceof PredicateLessThan)
+            || (direction.isDescending() && condition instanceof PredicateGreaterThan)) {
+            // we're asking for a <, <= query from ascending index or >, >= from descending
+            // we have to walk the lanes from bottom to up rather than up to bottom.
+            
+            lane = 0;
+            do {
+                stillLaning = lane < OrderedIndex.LANES;
+                nextkey = getPropertyNext(current, lane);
+                next = (Strings.isNullOrEmpty(nextkey)) 
+                    ? null 
+                    : new OrderedChildNodeEntry(nextkey, index.getChildNode(nextkey));
+                if ((next == null || !walkingPredicate.apply(next)) && lane < OrderedIndex.LANES) {
+                    // if we're currently pointing to NIL or the next element does not fit the search
+                    // but we still have lanes left
+                    lane++;
+                } else {
+                    if (condition.apply(next)) {
+                        found = next;
+                    } else {
+                        current = next;
+                        if (keepWalked && current != null) {
+                            walkedLanes[lane] = current;
                         }
                     }
-        return entry;
+                }
+            } while (((next != null && walkingPredicate.apply(next)) || stillLaning) && (found == null));
+        } else {
+            lane = OrderedIndex.LANES - 1;
+            
+            do {
+                stillLaning = lane > 0;
+                nextkey = getPropertyNext(current, lane);
+                next = (Strings.isNullOrEmpty(nextkey)) 
+                    ? null 
+                    : new OrderedChildNodeEntry(nextkey, index.getChildNode(nextkey));
+                if ((next == null || !walkingPredicate.apply(next)) && lane > 0) {
+                    // if we're currently pointing to NIL or the next element does not fit the search
+                    // but we still have lanes left, let's lower the lane;
+                    lane--;
+                } else {
+                    if (condition.apply(next)) {
+                        found = next;
+                    } else {
+                        current = next;
+                        if (keepWalked && current != null) {
+                            for (int l = lane; l >= 0; l--) {
+                                walkedLanes[l] = current;
+                            }
+                        }
+                    }
+                }
+            } while (((next != null && walkingPredicate.apply(next)) || stillLaning) && (found == null));
+        }
+        
+        return found;
     }
     
     /**
@@ -730,6 +811,11 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
         public boolean apply(ChildNodeEntry arg0) {
             return arg0 != null && searchfor.equals(arg0.getName());
         }
+
+        @Override
+        public String getSearchFor() {
+            return searchfor;
+        }
     }
     
     /**
@@ -760,6 +846,11 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
             
             return b;
         }
+        
+        @Override
+        public String getSearchFor() {
+            return searchfor;
+        }
     }
 
     /**
@@ -788,6 +879,11 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
 
             return b;
         }
+        
+        @Override
+        public String getSearchFor() {
+            return searchfor;
+        }
     }
     
     /**
@@ -838,23 +934,156 @@ public class OrderedContentMirrorStoreStrategy extends ContentMirrorStoreStrateg
                 
                 @Override
                 public boolean apply(String input) {
-                    return d.equals(OrderDirection.ASC) 
-                        ? v.compareTo(input) > 0 || (i && v.equals(input))
-                        : v.compareTo(input) < 0 || (i && v.equals(input));
+                    // splitting in multiple lines for easier debugging
+                    boolean compareTo, equals, apply;
+                    if (d.equals(OrderDirection.ASC)) {
+                        compareTo = v.compareTo(input) > 0;
+                    } else {
+                        compareTo = v.compareTo(input) < 0;
+                    }
+                    
+                    equals =  v.equals(input);
+                    apply = compareTo || (i && equals);
+                    return apply;
+                }
+
+                @Override
+                public String getSearchFor() {
+                    throw new UnsupportedOperationException();
                 }
             };
         }
 
         @Override
         public boolean hasNext() {
-            boolean next = super.hasNext();
+            boolean hasNext = super.hasNext();
             String name = getCurrentName();
             
-            if (name != null && next) {
-                name = convert(name);
-                next = next && condition.apply(name);
+            if (name != null && hasNext) {
+                String next = getPropertyNext(current);
+                hasNext = hasNext && condition.apply(next);
+            }
+            return hasNext;
+        }
+    }
+
+    /**
+     * set the value of the the :next at position 0
+     * 
+     * @param node the node to modify
+     * @param next the 'next' value
+     */
+    static void setPropertyNext(@Nonnull final NodeBuilder node, final String... next) {
+        if (node != null && next != null) {
+            String n1 = (next.length > 0) ? next[0] : "";
+            String n2 = (next.length > 1) ? next[1] : "";
+            String n3 = (next.length > 2) ? next[2] : "";
+            String n4 = (next.length > 3) ? next[3] : "";
+            
+            node.setProperty(NEXT, ImmutableList.of(n1, n2, n3, n4), Type.STRINGS);
+        }
+    }
+    
+    /**
+     * set the value of the :next at the given position. If the property :next won't be there by the
+     * time this method is invoked it won't perform any action
+     * 
+     * @param node
+     * @param value
+     * @param lane
+     */
+    static void setPropertyNext(@Nonnull final NodeBuilder node, 
+                                final String value, final int lane) {
+        if (node != null && value != null && lane >= 0 && lane < OrderedIndex.LANES) {
+            PropertyState next = node.getProperty(NEXT);
+            if (next != null) {
+                String[] values = Iterables.toArray(next.getValue(Type.STRINGS), String.class);
+                values[lane] = value;
+                setPropertyNext(node, values);
+            }
+        }
+    }
+
+    /**
+     * see {@link #getPropertyNext(NodeState, int)} by providing '0' as lane
+     */
+    static String getPropertyNext(@Nonnull final NodeState nodeState) {
+        return getPropertyNext(nodeState, 0);
+    }
+    
+    /**
+     * return the 'next' value at the provided position
+     * 
+     * @param nodeState the node state to inspect
+     * @return the next value
+     */
+    static String getPropertyNext(@Nonnull final NodeState state, final int lane) {
+        String next = "";
+        PropertyState ps = state.getProperty(NEXT);
+        if (ps != null) {
+            next = (lane < OrderedIndex.LANES) ? ps.getValue(Type.STRING, lane)
+                                               : "";
         }
         return next;
     }
+    
+    /**
+     * short-cut for using NodeBuilder. See {@code getNext(NodeState)}
+     */
+    static String getPropertyNext(@Nonnull final NodeBuilder node) {
+        return getPropertyNext(node.getNodeState());
+    }
+
+    /**
+     * short-cut for using NodeBuilder. See {@code getNext(NodeState)}
+     */
+    static String getPropertyNext(@Nonnull final NodeBuilder node, final int lane) {
+        return getPropertyNext(node.getNodeState(), lane);
+    }
+
+    /**
+     * short-cut for using ChildNodeEntry. See {@code getNext(NodeState)}
+     */
+    static String getPropertyNext(@Nonnull final ChildNodeEntry child) {
+        return getPropertyNext(child.getNodeState());
+    }
+
+    static String getPropertyNext(@Nonnull final ChildNodeEntry child, int lane) {
+        return getPropertyNext(child.getNodeState(), lane);
+    }
+
+    /**
+     * retrieve the lane to be updated based on probabilistic approach.
+     * 
+     * Having 4 lanes if we have the 3 to be updated it means we'll have to update lanes
+     * 0,1,2 and 3. If we'll have 2 only 0,1,2 and so on.
+     * 
+     * Lane 0 will always be updated as it's the base linked list.
+     * 
+     * It uses {@code getLane(Random)} by passing a {@code new Random(System.currentTimeMillis())}
+     * 
+     * @see OrderedIndex.DEFAULT_PROBABILITY
+     * 
+     * @return the lane to start updating from.
+     */
+    public int getLane() {
+        return getLane(RND);
+    }
+    
+    /**
+     * used for mocking purposes or advanced uses. Use the {@code getLane()} where possible
+     * 
+     * @param rnd the Random generator to be used for probability
+     * @return the lane to be updated. 
+     */
+    int getLane(@Nonnull final Random rnd) {
+        final int maxLanes = OrderedIndex.LANES - 1;
+        int lane = 0;
+        
+        while (rnd.nextDouble() < OrderedIndex.DEFAULT_PROBABILITY && lane < maxLanes) {
+            lane++;
+        }
+        
+        return lane;
     }
 }
\ No newline at end of file
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/BasicOrderedPropertyIndexQueryTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/BasicOrderedPropertyIndexQueryTest.java
index 734360a..8dc7a07 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/BasicOrderedPropertyIndexQueryTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/BasicOrderedPropertyIndexQueryTest.java
@@ -63,8 +63,7 @@ public abstract class BasicOrderedPropertyIndexQueryTest extends AbstractQueryTe
     /**
      * formatter for date conversions
      */
-    protected static final SimpleDateFormat ISO_8601_2000 = new SimpleDateFormat(
-        "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+    protected static final String ISO_8601_2000 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; 
 
     /**
      * generate a list of values to be used as ordered set. Will return something like
@@ -198,8 +197,9 @@ public abstract class BasicOrderedPropertyIndexQueryTest extends AbstractQueryTe
         List<String> values = new ArrayList<String>(amount);
         Calendar lstart = (Calendar) start.clone();
         int hours = (OrderDirection.DESC.equals(direction)) ? -12 : 12;
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
         for (int i = 0; i < amount; i++) {
-            values.add(ISO_8601_2000.format(lstart.getTime()));
+            values.add(sdf.format(lstart.getTime()));
             lstart.add(Calendar.HOUR_OF_DAY, hours);
         }
 
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
index 99b46ea..d0cd845 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexDescendingQueryTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertTrue;
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Iterator;
@@ -162,7 +163,7 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         
         // re-sorting descending for matching the actual index direction
         Collections.sort(nodes, Collections.reverseOrder());
@@ -206,7 +207,7 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         
         // re-sorting descending for matching the actual index direction
         Collections.sort(nodes, Collections.reverseOrder());
@@ -251,7 +252,7 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         Map<String, PropertyValue> filter = ImmutableMap.of(ORDERED_PROPERTY,
             PropertyValues.newDate(searchFor));
         Iterator<? extends ResultRow> results = executeQuery(
@@ -291,7 +292,7 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         Map<String, PropertyValue> filter = ImmutableMap.of(ORDERED_PROPERTY,
             PropertyValues.newDate(searchFor));
         Iterator<? extends ResultRow> results = executeQuery(
@@ -334,7 +335,7 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         
         // re-sorting descending for matching the actual index direction
         Collections.sort(nodes, Collections.reverseOrder());
@@ -372,12 +373,13 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -432,12 +434,13 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
         
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -479,12 +482,13 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
         
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -526,12 +530,13 @@ public class OrderedPropertyIndexDescendingQueryTest extends BasicOrderedPropert
 
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
index 6832bc9..86ebe9c 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexQueryTest.java
@@ -26,6 +26,7 @@ import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_N
 import static org.junit.Assert.assertNotNull;
 
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Iterator;
@@ -38,6 +39,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyValue;
@@ -172,7 +174,7 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         Map<String, PropertyValue> filter = ImmutableMap.of(ORDERED_PROPERTY,
             PropertyValues.newDate(searchFor));
         Iterator<? extends ResultRow> results = executeQuery(
@@ -211,7 +213,7 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         Map<String, PropertyValue> filter = ImmutableMap.of(ORDERED_PROPERTY,
             PropertyValues.newDate(searchFor));
         Iterator<? extends ResultRow> results = executeQuery(
@@ -229,8 +231,6 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
     /**
      * test the range query in case of '<' condition
      *
-     * in this case as we're ascending we're expecting an empty resultset with the proper
-     * provider. not the lowcost one.
      * @throws Exception
      */
     @Test
@@ -253,7 +253,7 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
 
         // re-sorting ascending as the index is ASC and the results will be returned as ASC
         Collections.sort(nodes);
@@ -309,7 +309,7 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         
         // re-sorting ascending as the index is ASC and the results will be returned as ASC
         Collections.sort(nodes);
@@ -677,7 +677,7 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendar = (Calendar) start.clone();
         searchForCalendar.add(Calendar.HOUR_OF_DAY, 36);
-        String searchFor = ISO_8601_2000.format(searchForCalendar.getTime());
+        String searchFor = new SimpleDateFormat(ISO_8601_2000).format(searchForCalendar.getTime());
         Iterator<? extends ResultRow> results = executeQuery(String.format(query, searchFor), SQL2,
             null).getRows().iterator();
         Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
@@ -711,12 +711,13 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf  = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -756,12 +757,13 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -801,12 +803,13 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
         
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -817,10 +820,6 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
             new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd, false, true))
             .iterator();
         
-        filtered = Iterables.filter(nodes,
-            new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd, false, true))
-            .iterator();
-        
         assertRightOrder(Lists.newArrayList(filtered), results);
         assertFalse("We should have looped throuhg all the results", results.hasNext());
 
@@ -850,12 +849,13 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
 
         Calendar searchForCalendarStart = (Calendar) start.clone();
         searchForCalendarStart.add(Calendar.HOUR_OF_DAY, 36);
-        String searchForStart = ISO_8601_2000.format(searchForCalendarStart.getTime());
+        SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_2000);
+        String searchForStart = sdf.format(searchForCalendarStart.getTime());
 
         Calendar endCalendar = Calendar.getInstance();
-        endCalendar.setTime(ISO_8601_2000.parse(nodes.get(nodes.size() - 1).getValue()));
+        endCalendar.setTime(sdf.parse(nodes.get(nodes.size() - 1).getValue()));
         endCalendar.add(Calendar.HOUR_OF_DAY, -36);
-        String searchForEnd = ISO_8601_2000.format(endCalendar.getTime());
+        String searchForEnd = sdf.format(endCalendar.getTime());
 
         Map<String, PropertyValue> filter = ImmutableMap.of("start",
             PropertyValues.newDate(searchForStart), "end", PropertyValues.newDate(searchForEnd));
@@ -863,10 +863,6 @@ public class OrderedPropertyIndexQueryTest extends BasicOrderedPropertyIndexQuer
             .iterator();
 
         Iterator<ValuePathTuple> filtered = Iterables.filter(nodes,
-            new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd, false, true))
-            .iterator();
-
-        filtered = Iterables.filter(nodes,
             new ValuePathTuple.BetweenPredicate(searchForStart, searchForEnd, true, true))
             .iterator();
         
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
index bfc2de0..3b21c55 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/OrderedContentMirrorStorageStrategyTest.java
@@ -20,32 +20,48 @@ 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.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
 import java.util.Set;
 
+import javax.annotation.Nonnull;
 import javax.jcr.RepositoryException;
 
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
 import org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex;
 import org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
+import org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy.OrderedChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy.PredicateLessThan;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.query.ast.Operator;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -56,14 +72,52 @@ import com.google.common.collect.Iterators;
  *
  */
 public class OrderedContentMirrorStorageStrategyTest {
+    private static final Logger LOG = LoggerFactory.getLogger(OrderedContentMirrorStorageStrategyTest.class);
+    
     /**
      * ascending ordered set of keys. Useful for testing
      */
-    private static final String[] KEYS = new String[] { "donald", "goofy", "mickey", "minnie" };
+    private static final String[] KEYS = new String[] { "000", "001", "002", "003", "004", "005",
+                                                       "006", "007", "008", "009", "010", "011",
+                                                       "012", "013", "014", };
     private static final Set<String> EMPTY_KEY_SET = newHashSet();
     private static final NumberFormat NF = new DecimalFormat("00000");
     
     /**
+     * convenience class for mocking some behaviours while testing
+     */
+    private static class MockOrderedContentMirrorStoreStrategy extends
+        OrderedContentMirrorStoreStrategy {
+        
+        public MockOrderedContentMirrorStoreStrategy() {
+            super();
+        }
+
+        public MockOrderedContentMirrorStoreStrategy(OrderDirection direction) {
+            super(direction);
+        }
+
+        /**
+         * tells the code to use the Original class method implementation
+         */
+        public static final int SUPER_LANE = -1;
+        private int lane = SUPER_LANE;
+
+        @Override
+        public int getLane() {
+            if (lane == SUPER_LANE) {
+                return super.getLane();
+            } else {
+                return lane;
+            }
+        }
+        
+        public void setLane(int lane) {
+            this.lane = lane; 
+        }
+    }
+
+    /**
      * checks that the fist item/key is inserted with an empty property 'next'
      *
      * expected structure:
@@ -95,11 +149,13 @@ public class OrderedContentMirrorStorageStrategyTest {
         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", no, node.getString(NEXT));
+        assertEquals(":start should point to n0", no,
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         node = index.getChildNode(no);
         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));
+        assertEquals("n0 should point nowhere as it's the last (and only) element", "",
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         // checking content structure below n0
         node = node.getChildNode(pathNodes[0]);
@@ -137,26 +193,31 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         node = index.getChildNode(START);
         assertTrue(":index should have :start", node.exists());
-        assertEquals(":start should point to n0", n0, node.getString(NEXT));
+        assertEquals(":start should point to n0", n0, 
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         node = index.getChildNode(n0);
         assertTrue(":index should have n0", node.exists());
-        assertEquals("n0 should point nowhere at this stage", "", node.getString(NEXT));
+        assertEquals("n0 should point nowhere at this stage", "",
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         // second node arrives
         store.update(index, path, EMPTY_KEY_SET, newHashSet(n1));
 
         node = index.getChildNode(START);
         assertTrue(":index should still have :start", node.exists());
-        assertEquals(":start should still point to n0", n0, node.getString(NEXT));
+        assertEquals(":start should still point to n0", n0,
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         node = index.getChildNode(n0);
         assertTrue("n0 should still exists", node.exists());
-        assertEquals("n0 should point to n1", n1, node.getString(NEXT));
+        assertEquals("n0 should point to n1", n1,
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
 
         node = index.getChildNode(n1);
         assertTrue("n1 should exists", node.exists());
-        assertEquals("n1 should point nowhere", "", node.getString(NEXT));
+        assertEquals("n1 should point nowhere", "",
+            Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
     }
 
     /**
@@ -358,7 +419,9 @@ public class OrderedContentMirrorStorageStrategyTest {
      */
     @Test
     public void childNodeEntriesNewIndexWithStart() {
-        NodeState nodeStart = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
+        NodeState nodeStart = EmptyNodeState.EMPTY_NODE.builder()
+            .setProperty(NEXT, OrderedContentMirrorStoreStrategy.EMPTY_NEXT, Type.STRINGS)
+            .getNodeState();
         NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
         OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
 
@@ -425,7 +488,8 @@ public class OrderedContentMirrorStorageStrategyTest {
         // 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));
+        assertEquals(":start is expected to point to the 1st node", key1st,
+            Iterables.toArray(ns.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
         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)));
@@ -433,12 +497,14 @@ public class OrderedContentMirrorStorageStrategyTest {
         // 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));
+        assertEquals(":start is expected to point to the 2nd node", key2nd,
+            Iterables.toArray(ns.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
         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));
+        assertEquals("At Stage 2 the second element should point to the first one", key1st,
+            Iterables.toArray(ns.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
     }
 
     /**
@@ -516,30 +582,48 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         // 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));
+        NodeState n = index.getChildNode(START).getNodeState();
+        assertEquals(":start should point to the first node", n0, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
         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));
+        n = index.getChildNode(START).getNodeState();
+        assertEquals(":start should point to n1", n1, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        n = index.getChildNode(n1).getNodeState();
+        assertEquals("'n1' should point to 'n0'", n0,
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
         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)));
+        n = index.getChildNode(START).getNodeState();
+        assertEquals(":start should point to n1", n1, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        n = index.getChildNode(n1).getNodeState();
+        assertEquals("n1 should be pointing to n2", n2, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        n = index.getChildNode(n2).getNodeState();
+        assertEquals("n2 should be pointing to n0", n0,
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        n = index.getChildNode(n0).getNodeState();
+        assertTrue("n0 should still be the last item of the list", Strings.isNullOrEmpty(Iterables
+            .toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]));
 
         // 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)));
+        n = index.getChildNode(START).getNodeState();
+        assertEquals(":start should point to n1", n1, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        n = index.getChildNode(n1).getNodeState();
+        assertEquals("n1 should be pointing to n2", n2, 
+            Iterables.toArray(n.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0]);
+        assertEquals("n2 should be pointing to n0", n0, getNext(index.getChildNode(n2)));
+        assertEquals("n0 should be pointing to n3", n3, getNext(index.getChildNode(n0)));
+        assertTrue("n3 should be the last element",
+            Strings.isNullOrEmpty(getNext(index.getChildNode(n3))));
     }
 
     /**
@@ -596,11 +680,11 @@ public class OrderedContentMirrorStorageStrategyTest {
         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));
+        assertEquals(":start should point to n0", n0, getNext(node));
 
         node = index.getChildNode(n0);
         assertTrue(":index should have n0", node.exists());
-        assertTrue("n0 should point nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+        assertTrue("n0 should point nowhere", Strings.isNullOrEmpty(getNext(node)));
 
         node = node.getChildNode(nodes[0]);
         assertTrue("n0 should have /content", node.exists());
@@ -612,11 +696,11 @@ public class OrderedContentMirrorStorageStrategyTest {
         // 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));
+        assertEquals(":start should now point to n1", n1, getNext(node));
 
         node = index.getChildNode(n1);
         assertTrue("n1 should exists", node.exists());
-        assertTrue("n1 should point nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+        assertTrue("n1 should point nowhere", Strings.isNullOrEmpty(getNext(node)));
 
         node = node.getChildNode(nodes[0]);
         assertTrue("n1 should have /content", node.exists());
@@ -627,40 +711,6 @@ public class OrderedContentMirrorStorageStrategyTest {
     }
 
     /**
-     * <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 nodeStart = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, n0).getNodeState();
-        final NodeState node0 = EmptyNodeState.EMPTY_NODE.builder().setProperty(NEXT, "").getNodeState();
-        final NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
-
-        index.setChildNode(START, nodeStart);
-        index.setChildNode(n0, node0);
-
-        NodeState indexState = index.getNodeState();
-        ChildNodeEntry previous = store.findPrevious(indexState, node0);
-        assertNotNull(previous);
-        assertEquals("the :start node is expected", nodeStart, previous.getNodeState());
-    }
-
-    /**
      * test the use case where a document change the indexed property. For
      * example document that change author.
      *
@@ -723,10 +773,10 @@ public class OrderedContentMirrorStorageStrategyTest {
         assertFalse(index.hasChildNode(n1));
 
         NodeBuilder node = index.getChildNode(START);
-        assertEquals(":start pointing to wrong node", n0, node.getString(NEXT));
+        assertEquals(":start pointing to wrong node", n0, getNext(node));
 
         node = index.getChildNode(n0);
-        assertTrue("n0 should go nowhere", Strings.isNullOrEmpty(node.getString(NEXT)));
+        assertTrue("n0 should go nowhere", Strings.isNullOrEmpty(getNext(node)));
 
         // checking the first document
         String[] path = Iterables.toArray(PathUtils.elements(path0), String.class);
@@ -750,10 +800,10 @@ public class OrderedContentMirrorStorageStrategyTest {
         assertTrue(index.hasChildNode(n1));
 
         node = index.getChildNode(START);
-        assertEquals(":start pointing to wrong node", n0, node.getString(NEXT));
+        assertEquals(":start pointing to wrong node", n0, getNext(node));
 
         node = index.getChildNode(n0);
-        assertEquals(n1, node.getString(NEXT));
+        assertEquals(n1, getNext(node));
         path = Iterables.toArray(PathUtils.elements(path0), String.class);
         node = node.getChildNode(path[0]);
         assertTrue(node.exists());
@@ -877,8 +927,8 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         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)));
+        assertEquals(":start should still point to n0", n0, getNext(index.getChildNode(START)));
+        assertTrue("n0 should point nowhere", Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
 
         assertFalse(index.getChildNode(n0).hasChildNode(doc1));
         assertTrue(index.getChildNode(n0).hasChildNode(doc2));
@@ -970,9 +1020,9 @@ public class OrderedContentMirrorStorageStrategyTest {
         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)));
+        assertEquals(n1, getNext(index.getChildNode(START)));
+        assertEquals(n0, getNext(index.getChildNode(n1)));
+        assertTrue(Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
 
         // checking sub-nodes
         String[] subNodes = Iterables.toArray(PathUtils.elements(path0), String.class);
@@ -1008,11 +1058,11 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
-        assertEquals(":start should point to the first node", n0, index.getChildNode(START)
-                                                                       .getString(NEXT));
-        assertEquals("n0 should point to n1", n1, index.getChildNode(n0).getString(NEXT));
+        assertEquals(":start should point to the first node", n0,
+            getNext(index.getChildNode(START)));
+        assertEquals("n0 should point to n1", n1, getNext(index.getChildNode(n0)));
         assertTrue("n1 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n1).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n1))));
     }
 
     /**
@@ -1070,84 +1120,33 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         // Stage 1
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
-        assertEquals(":start should point to n0", n0, index.getChildNode(START).getString(NEXT));
+        assertEquals(":start should point to n0", n0, getNext(index.getChildNode(START)));
         assertTrue("n0 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
 
         // 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));
+        assertEquals(":start should point to n1", n1, getNext(index.getChildNode(START)));
+        assertEquals("n1 should point to n0", n0, getNext(index.getChildNode(n1)));
         assertTrue("n0 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
 
         // Stage 3
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
-        assertEquals(":start should point to n2", n2, index.getChildNode(START).getString(NEXT));
-        assertEquals("n2 should point to n1", n1, index.getChildNode(n2).getString(NEXT));
-        assertEquals("n1 should point to n0", n0, index.getChildNode(n1).getString(NEXT));
+        assertEquals(":start should point to n2", n2, getNext(index.getChildNode(START)));
+        assertEquals("n2 should point to n1", n1, getNext(index.getChildNode(n2)));
+        assertEquals("n1 should point to n0", n0, getNext(index.getChildNode(n1)));
         assertTrue("n0 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
 
         // Stage 4
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
-        assertEquals(":start should point to n3", n3, index.getChildNode(START).getString(NEXT));
-        assertEquals("n3 should point to n2", n2, index.getChildNode(n3).getString(NEXT));
-        assertEquals("n2 should point to n1", n1, index.getChildNode(n2).getString(NEXT));
-        assertEquals("n1 should point to n0", n0, index.getChildNode(n1).getString(NEXT));
+        assertEquals(":start should point to n3", n3, getNext(index.getChildNode(START)));
+        assertEquals("n3 should point to n2", n2, getNext(index.getChildNode(n3)));
+        assertEquals("n2 should point to n1", n1, getNext(index.getChildNode(n2)));
+        assertEquals("n1 should point to n0", n0, getNext(index.getChildNode(n1)));
         assertTrue("n0 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
-    }
-
-    /**
-     * test finding a previous item in a descending ordered index.
-     *
-     * <code>
-     *      Stage 1
-     *      =======
-     *
-     *      :index {
-     *          :start : { :next=n0 },
-     *          n0 : { :next= }
-     *      }
-     *
-     *      findPrevious(n0)=:start
-     *
-     *      Stage 2
-     *      =======
-     *
-     *      :index {
-     *          :start : { :next=n1 },
-     *          n0 : { :next= }
-     *          n1 : { :next=n0 }
-     *      }
-     *
-     *      findPrevious(n0)=n1;
-     * </code>
-     */
-    @Test
-    public void descendingOrderFindPrevious() {
-        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy(OrderDirection.DESC);
-        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
-        String n0 = KEYS[0];
-        String n1 = KEYS[1];
-        NodeState indexState;
-        NodeState previous;
-        NodeState node;
-
-        //Stage 1
-        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
-        indexState = index.getNodeState();
-        node = indexState.getChildNode(n0);
-        previous = indexState.getChildNode(START);
-        assertEquals(previous, store.findPrevious(indexState, node).getNodeState());
-
-        //Stage 2
-        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
-        indexState = index.getNodeState();
-        node = indexState.getChildNode(n0);
-        previous = indexState.getChildNode(n1);
-        assertEquals(previous, store.findPrevious(indexState, node).getNodeState());
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
     }
 
     /**
@@ -1170,10 +1169,10 @@ public class OrderedContentMirrorStorageStrategyTest {
         String n0 = KEYS[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));
+        assertEquals(":start should point to the first node", n0,
+            getNext(index.getChildNode(START)));
         assertTrue("the first node should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n0).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n0))));
     }
 
     /**
@@ -1204,12 +1203,12 @@ public class OrderedContentMirrorStorageStrategyTest {
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
-        assertEquals(":start should point to n1", n1, index.getChildNode(START).getString(NEXT));
-        assertEquals("n0 should point to n3", n3, index.getChildNode(n0).getString(NEXT));
-        assertEquals("n1 should point to n2", n2, index.getChildNode(n1).getString(NEXT));
-        assertEquals("n2 should point to n1", n0, index.getChildNode(n2).getString(NEXT));
+        assertEquals(":start should point to n1", n1, getNext(index.getChildNode(START)));
+        assertEquals("n0 should point to n3", n3, getNext(index.getChildNode(n0)));
+        assertEquals("n1 should point to n2", n2, getNext(index.getChildNode(n1)));
+        assertEquals("n2 should point to n1", n0, getNext(index.getChildNode(n2)));
         assertTrue("n3 should point nowhere",
-                   Strings.isNullOrEmpty(index.getChildNode(n3).getString(NEXT)));
+                   Strings.isNullOrEmpty(getNext(index.getChildNode(n3))));
     }
 
     /**
@@ -1378,7 +1377,7 @@ public class OrderedContentMirrorStorageStrategyTest {
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
 
-        assertNull("The item should have not been found", OrderedContentMirrorStoreStrategy.seek(
+        assertNull("The item should have not been found", store.seek(
             index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateEquals(nonExisting)));
     }
@@ -1400,7 +1399,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n1;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor));
 
         assertNotNull("we should have found an item", item);
@@ -1424,7 +1423,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n1;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor));
 
         assertNull("no item should have been found", item);
@@ -1445,9 +1444,11 @@ public class OrderedContentMirrorStorageStrategyTest {
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n2));
         store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n3));
 
+        printSkipList(index.getNodeState());
+        
         String searchFor = n2;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor));
 
         assertNotNull("we should have found an item", item);
@@ -1469,7 +1470,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = KEYS[3];
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor, true));
 
         assertNull("we should have not found an item", item);
@@ -1490,7 +1491,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n2;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateGreaterThan(searchFor, true));
 
         assertNotNull("we should have found an item", item);
@@ -1513,7 +1514,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n3;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor));
 
         assertNull("we should have not found an item", item);
@@ -1535,7 +1536,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n2;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor));
 
         assertNotNull("we should have found an item", item);
@@ -1558,7 +1559,7 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = KEYS[0];
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor, true));
 
         assertNull("we should have not found an item", item);
@@ -1580,10 +1581,2039 @@ public class OrderedContentMirrorStorageStrategyTest {
 
         String searchFor = n2;
 
-        ChildNodeEntry item = OrderedContentMirrorStoreStrategy.seek(index.getNodeState(),
+        ChildNodeEntry item = store.seek(index.getNodeState(),
             new OrderedContentMirrorStoreStrategy.PredicateLessThan(searchFor, true));
 
         assertNotNull("we should have found an item", item);
         assertEquals(n2, item.getName());
     }
+    
+    private static String getNext(@Nonnull NodeBuilder node) {
+        return getNext(node.getNodeState());
+    }
+    
+    private static String getNext(@Nonnull NodeState node) {
+        return Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[0];
+    }
+
+    private static String getNext(@Nonnull NodeState node, int lane) {
+        return Iterables.toArray(node.getProperty(NEXT).getValue(Type.STRINGS), String.class)[lane];
+    }
+
+    private static Iterable<String> getMultiNext(@Nonnull NodeState node) {
+        return node.getProperty(NEXT).getValue(Type.STRINGS);
+    }
+    
+    @Test
+    public void setNext() {
+        NodeBuilder n = EmptyNodeState.EMPTY_NODE.builder();
+        
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "foobar");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("foobar", "", "", ""), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, (String[]) null);
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals("If I set a value to null, nothing should change",
+            ImmutableList.of("foobar", "", "", ""), n.getProperty(NEXT).getValue(Type.STRINGS));
+
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("", "", "", ""), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "a", "b");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("a", "b", "", ""), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+
+        n = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "a", "b", "c");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("a", "b", "c", ""), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+
+        n = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "a", "b", "c", "d");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("a", "b", "c", "d"), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+
+        n = EmptyNodeState.EMPTY_NODE.builder();
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "a", "b", "c", "d", "e", "f");
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals("even if we provide more than 4 nexts we expect it to take only the first 4s", 
+            ImmutableList.of("a", "b", "c", "d"), 
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = EmptyNodeState.EMPTY_NODE.builder();
+        n.setProperty(NEXT, ImmutableList.of("a", "b", "c", "d"), Type.STRINGS);
+        OrderedContentMirrorStoreStrategy.setPropertyNext(n, "a", 3);
+        assertNotNull(n);
+        assertNotNull(":next cannot be null", n.getProperty(NEXT));
+        assertEquals(ImmutableList.of("a", "b", "c", "a"),
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+    }
+    
+    @Test
+    public void getNext() {
+        NodeBuilder node = EmptyNodeState.EMPTY_NODE.builder();
+        assertEquals("If the property is not there an empty string is expected", "",
+            OrderedContentMirrorStoreStrategy.getPropertyNext(node.getNodeState()));
+        
+        node.setProperty(NEXT, ImmutableList.of("bar", "", "", ""), Type.STRINGS);
+        assertEquals("bar", OrderedContentMirrorStoreStrategy.getPropertyNext(node.getNodeState()));
+
+        node.setProperty(NEXT, ImmutableList.of("", "", "", ""), Type.STRINGS);
+        assertEquals("", OrderedContentMirrorStoreStrategy.getPropertyNext(node.getNodeState()));
+        
+        node = EmptyNodeState.EMPTY_NODE.builder();
+        assertEquals("If the property is not there an empty string is expected", "",
+            OrderedContentMirrorStoreStrategy.getPropertyNext(node));
+        
+        node.setProperty(NEXT, ImmutableList.of("bar", "", "", ""), Type.STRINGS);
+        assertEquals("bar", OrderedContentMirrorStoreStrategy.getPropertyNext(node));
+
+        node.setProperty(NEXT, ImmutableList.of("", "", "", ""), Type.STRINGS);
+        assertEquals("", OrderedContentMirrorStoreStrategy.getPropertyNext(node));
+        
+        node.setProperty(NEXT, ImmutableList.of("a", "b", "c", "d"), Type.STRINGS);
+        assertEquals("a", OrderedContentMirrorStoreStrategy.getPropertyNext(node));
+        assertEquals("a", OrderedContentMirrorStoreStrategy.getPropertyNext(node, 0));
+        assertEquals("b", OrderedContentMirrorStoreStrategy.getPropertyNext(node, 1));
+        assertEquals("c", OrderedContentMirrorStoreStrategy.getPropertyNext(node, 2));
+        assertEquals("d", OrderedContentMirrorStoreStrategy.getPropertyNext(node, 3));
+        assertEquals("if we provide a number outside the range an empty next is expeted", "",
+            OrderedContentMirrorStoreStrategy.getPropertyNext(node, OrderedIndex.LANES + 100));
+    }
+    
+    @Test
+    public void getLane() {
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        Random generator = null;
+        
+        // Default probability is 0.1
+        
+        generator = createNiceMock(Random.class);
+        expect(generator.nextDouble()).andReturn(0.73).anyTimes();
+        replay(generator);        
+        assertEquals(0, store.getLane(generator));
+        
+        generator = createNiceMock(Random.class);
+        expect(generator.nextDouble()).andReturn(0.02).once();
+        expect(generator.nextDouble()).andReturn(0.73).once();
+        replay(generator);
+        assertEquals(1, store.getLane(generator));
+
+        generator = createNiceMock(Random.class);
+        expect(generator.nextDouble()).andReturn(0.02).times(2);
+        expect(generator.nextDouble()).andReturn(0.73).once();
+        replay(generator);
+        assertEquals(2, store.getLane(generator));
+
+        generator = createNiceMock(Random.class);
+        expect(generator.nextDouble()).andReturn(0.02).times(3);
+        expect(generator.nextDouble()).andReturn(0.73).once();
+        replay(generator);
+        assertEquals(3, store.getLane(generator));
+
+        generator = createNiceMock(Random.class);
+        expect(generator.nextDouble()).andReturn(0.02).times(OrderedIndex.LANES);
+        expect(generator.nextDouble()).andReturn(0.73).once();
+        replay(generator);
+        assertEquals("we should never go beyond 4 lanes", OrderedIndex.LANES - 1,
+            store.getLane(generator));
+    }
+    
+    /**
+     * Test the insert of 1 item into an empty index. Start should always point with all the lanes
+     * to the first element
+     * 
+     */
+    @Test
+    public void insertWithLanes1Item() {
+        MockOrderedContentMirrorStoreStrategy store = new MockOrderedContentMirrorStoreStrategy();
+        NodeBuilder index = EmptyNodeState.EMPTY_NODE.builder();
+        String n0 = KEYS[0];
+        
+       
+        /*
+         * with lane==0
+         * 
+         *  :index : {
+         *      :start : { :next = [n0, , , ] },
+         *      n0 : { :next = [ , , , ] }
+         *  }
+         */
+        store.setLane(0);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        
+        NodeBuilder n = index.getChildNode(START);
+        assertNotNull("There should always be a :start", n);
+        assertEquals(":start's :next should always point to the first element", 
+            ImmutableList.of(n0, "", "", ""),
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        n = index.getChildNode(n0);
+        assertNotNull(n);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        
+        /*
+         * with lane==1
+         * 
+         *  :index : {
+         *      :start : { :next = [n0, n0, , ] },
+         *      n0 : { :next = [ , , , ] }
+         *  }
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(1);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        
+        n = index.getChildNode(START);
+        assertNotNull("There should always be a :start", n);
+        assertEquals(":start's :next should always point to the first element", 
+            ImmutableList.of(n0, n0, "", ""),
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        n = index.getChildNode(n0);
+        assertNotNull(n);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+
+        /*
+         * with lane==2
+         * 
+         *  :index : {
+         *      :start : { :next = [n0, n0, n0, ] },
+         *      n0 : { :next = [ , , , ] }
+         *  }
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(2);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        
+        n = index.getChildNode(START);
+        assertNotNull("There should always be a :start", n);
+        assertEquals(":start's :next should always point to the first element", 
+            ImmutableList.of(n0, n0, n0, ""),
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        n = index.getChildNode(n0);
+        assertNotNull(n);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        
+        /*
+         * with lane==3
+         * 
+         *  :index : {
+         *      :start : { :next = [n0, n0, n0, n0 ] },
+         *      n0 : { :next = [ , , , ] }
+         *  }
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(3);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        
+        n = index.getChildNode(START);
+        assertNotNull("There should always be a :start", n);
+        assertEquals(":start's :next should always point to the first element", 
+            ImmutableList.of(n0, n0, n0, n0),
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+        n = index.getChildNode(n0);
+        assertNotNull(n);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS)
+        );
+    }
+    
+
+    /**
+     * tests the insert of an item that has to be appended 
+     */
+    @Test 
+    public void laneInsert2ItemsAlreadyOrdere() {
+        MockOrderedContentMirrorStoreStrategy store = new MockOrderedContentMirrorStoreStrategy();
+        NodeBuilder index = null;
+        NodeBuilder n = null;
+        String n0 = KEYS[0];
+        String n1 = KEYS[1];
+        
+        // this one should be covered by insertWithLanes1Item(). Not testing
+        
+        /* 
+         * if lane is 0 we're expecting the following
+         * 
+         *  :index : {
+         *      :start  : { :next : [n0, , , ] },
+         *      n0      : { :next : [n1, , , ] }
+         *      n1      : { :next : [ , , , ] }
+         *  }
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(0);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+        printSkipList(index.getNodeState());
+        n = index.getChildNode(START); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(ImmutableList.of(n0, "", "", ""), n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = index.getChildNode(n0); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(ImmutableList.of(n1, "", "", ""), n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = index.getChildNode(n1); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /* 
+         * if lane == 1 on n1 insert
+         * 
+         *  :index : {
+         *      :start  : { :next : [n0, n1, , ] },
+         *      n0      : { :next : [n1, , , ] }
+         *      n1      : { :next : [ , , , ] }
+         *  }
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(0);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n0));
+        store.setLane(1);
+        store.update(index, "/a/b", EMPTY_KEY_SET, newHashSet(n1));
+        printSkipList(index.getNodeState());
+        n = index.getChildNode(START); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(ImmutableList.of(n0, n1, "", ""), n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = index.getChildNode(n0); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(ImmutableList.of(n1, "", "", ""), n.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        n = index.getChildNode(n1); 
+        assertNotNull(n);
+        assertNotNull(n.getProperty(NEXT));
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            n.getProperty(NEXT).getValue(Type.STRINGS));
+    }
+    
+    /**
+     * Testing The Insert Of Shuffled Items And Lanes Recreating The Following Index Structure
+     * 
+     *  <Code>
+     *      List Structure
+     *      ==============
+     *      (Above The Node Names Is The Insert Order)
+     *      
+     *              9   5   6   4   7   1   0   3   10  2   12  11  8
+     *         -----------------------------------------------------------
+     *         Str 000 001 002 003 004 005 006 007 008 009 010 011 012 Nil
+     *          |-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->|
+     *          |------>o------>o------>o------>o---------->o---------->|
+     *          |-------------->o-------------->o---------->o---------->|
+     *          |------------------------------------------>o---------->|
+     *  </Code>
+     */
+    @Test
+    public void insertShuffledItemsWithLanes() {
+        MockOrderedContentMirrorStoreStrategy ascStore = new MockOrderedContentMirrorStoreStrategy();
+        MockOrderedContentMirrorStoreStrategy descStore = new MockOrderedContentMirrorStoreStrategy(
+            OrderDirection.DESC);
+        NodeBuilder ascIndex = EmptyNodeState.EMPTY_NODE.builder();
+        NodeBuilder descIndex = EmptyNodeState.EMPTY_NODE.builder();
+        NodeBuilder node;
+        NodeBuilder index;
+        String n00 = KEYS[0];
+        String n01 = KEYS[1];
+        String n02 = KEYS[2];
+        String n03 = KEYS[3];
+        String n04 = KEYS[4];
+        String n05 = KEYS[5];
+        String n06 = KEYS[6];
+        String n07 = KEYS[7];
+        String n08 = KEYS[8];
+        String n09 = KEYS[9];
+        String n10 = KEYS[10];
+        String n11 = KEYS[11];
+        String n12 = KEYS[12];
+        
+        /*
+         * Stage 0
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n06));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n06));
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = descIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = descIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        /*
+         * Stage 1
+         */
+        ascStore.setLane(1);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n05));
+        descStore.setLane(1);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n05));
+
+        index = ascIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 2
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n09));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n09));
+        
+        index = ascIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n05, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 3
+         */
+        ascStore.setLane(2);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n07));
+        descStore.setLane(2);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n07));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(OrderedContentMirrorStoreStrategy.EMPTY_NEXT,
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 4
+         */
+        ascStore.setLane(2);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n03));
+
+        descStore.setLane(2);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n03));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, n03, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 5
+         */
+        ascStore.setLane(1);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n01));
+        descStore.setLane(1);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n01));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 6
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n02));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n02));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 7
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n04));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n04));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 8
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n12));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n12));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 9
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n00));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n00));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /**
+         * Stage 10
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n08));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n08));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /**
+         * Stage 11
+         */
+        ascStore.setLane(0);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n11));
+        descStore.setLane(0);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n11));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, n01, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n11, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n11);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n11, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n11);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        /*
+         * Stage 12
+         */
+        ascStore.setLane(3);
+        ascStore.update(ascIndex, "/a", EMPTY_KEY_SET, newHashSet(n10));
+        descStore.setLane(3);
+        descStore.update(descIndex, "/a", EMPTY_KEY_SET, newHashSet(n10));
+
+        node = ascIndex.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, n01, n03, n10),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n05, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n07, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, n10, n10, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        
+        node = ascIndex.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n10, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n10);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n11, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n11);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        node = ascIndex.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+
+        index = descIndex;
+        node = index.getChildNode(START);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n12, n10, n10, n10),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n12);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n11, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n11);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n10, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n10);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n09, n07, n07, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n09);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n08, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n08);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n07, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n07);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n06, n05, n03, ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n06);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n05, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n05);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n04, n03, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n04);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n03, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n03);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n02, n01, "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n02);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n01, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n01);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of(n00, "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n00);
+        assertNotNull(node);
+        assertEquals(ImmutableList.of("", "", "", ""),
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+    }
+    
+    /**
+     * testing the seek method and the returned lanes with the following index structure
+     * 
+     *  <code>
+     *      List Structure
+     *      ==============
+     *      
+     *         STR 000 001 002 003 004 005 006 007 008 009 010 011 012 NIL
+     *          |-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->|
+     *          |------>o------>o------>o------>o---------->o---------->|
+     *          |-------------->o-------------->o---------->o---------->|
+     *          |------------------------------------------>o---------->|
+     *  </code>
+     */
+    @Test
+    public void seekEqualsWithLanes() {
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy();
+        NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        String n00 = KEYS[0];
+        String n01 = KEYS[1];
+        String n02 = KEYS[2];
+        String n03 = KEYS[3];
+        String n04 = KEYS[4];
+        String n05 = KEYS[5];
+        String n06 = KEYS[6];
+        String n07 = KEYS[7];
+        String n08 = KEYS[8];
+        String n09 = KEYS[9];
+        String n10 = KEYS[10];
+        String n11 = KEYS[11];
+        String n12 = KEYS[12];
+
+        // initialising the store
+        builder.child(START).setProperty(NEXT, ImmutableList.of(n00, n01, n03, n10), Type.STRINGS);
+        builder.child(n00).setProperty(NEXT,   ImmutableList.of(n01,  "",  "",  ""), Type.STRINGS);
+        builder.child(n01).setProperty(NEXT,   ImmutableList.of(n02, n03,  "",  ""), Type.STRINGS);
+        builder.child(n02).setProperty(NEXT,   ImmutableList.of(n03,  "",  "",  ""), Type.STRINGS);
+        builder.child(n03).setProperty(NEXT,   ImmutableList.of(n04, n05, n07,  ""), Type.STRINGS);
+        builder.child(n04).setProperty(NEXT,   ImmutableList.of(n05,  "",  "",  ""), Type.STRINGS);
+        builder.child(n05).setProperty(NEXT,   ImmutableList.of(n06, n07,  "",  ""), Type.STRINGS);
+        builder.child(n06).setProperty(NEXT,   ImmutableList.of(n07,  "",  "",  ""), Type.STRINGS);
+        builder.child(n07).setProperty(NEXT,   ImmutableList.of(n08, n10, n10,  ""), Type.STRINGS);
+        builder.child(n08).setProperty(NEXT,   ImmutableList.of(n09,  "",  "",  ""), Type.STRINGS);
+        builder.child(n09).setProperty(NEXT,   ImmutableList.of(n10, n12,  "",  ""), Type.STRINGS);
+        builder.child(n10).setProperty(NEXT,   ImmutableList.of(n11,  "",  "",  ""), Type.STRINGS);
+        builder.child(n11).setProperty(NEXT,   ImmutableList.of(n12,  "",  "",  ""), Type.STRINGS);
+        builder.child(n12).setProperty(NEXT,   ImmutableList.of("" ,  "",  "",  ""), Type.STRINGS);
+
+        NodeState index = builder.getNodeState();
+        
+        printSkipList(index);
+
+        // testing the exception in case of wrong parameters
+        String searchFor = "wedontcareaswetesttheexception";
+        NodeState node = index.getChildNode(searchFor);
+        ChildNodeEntry entry = new OrderedChildNodeEntry(
+            searchFor, node);
+        ChildNodeEntry[] wl = new ChildNodeEntry[0];
+        ChildNodeEntry item = null;
+        ChildNodeEntry lane0, lane1, lane2, lane3;
+        
+        try {
+            item = store.seek(index,
+                new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+            fail("With a wrong size for the lane it should have raised an exception");
+        } catch (IllegalArgumentException e) {
+            // so far so good. It was expected
+        }
+        
+        // testing equality
+        searchFor = n12;
+        lane3 = new OrderedChildNodeEntry(n10, index.getChildNode(n10));
+        lane2 = new OrderedChildNodeEntry(n10, index.getChildNode(n10));
+        lane1 = new OrderedChildNodeEntry(n10, index.getChildNode(n10));
+        lane0 = new OrderedChildNodeEntry(n11, index.getChildNode(n11));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+
+        searchFor = n08;
+        lane3 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane2 = new OrderedChildNodeEntry(n07, index.getChildNode(n07));
+        lane1 = new OrderedChildNodeEntry(n07, index.getChildNode(n07));
+        lane0 = new OrderedChildNodeEntry(n07, index.getChildNode(n07));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+
+        searchFor = n06;
+        lane3 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane2 = new OrderedChildNodeEntry(n03, index.getChildNode(n03));
+        lane1 = new OrderedChildNodeEntry(n05, index.getChildNode(n05));
+        lane0 = new OrderedChildNodeEntry(n05, index.getChildNode(n05));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+    }
+
+    /**
+     * testing the seek method and the returned lanes with the following index structure
+     * 
+     *  <code>
+     *      List Structure
+     *      ==============
+     *      
+     *         STR 012 011 010 009 008 007 006 005 004 003 002 001 000 NIL
+     *          |-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->o-->|
+     *          |------>o------>o------>o------>o---------->o---------->|
+     *          |-------------->o-------------->o---------->o---------->|
+     *          |------------------------------------------>o---------->|
+     *  </code>
+     */
+    @Test
+    public void seekEqualsWithLanesDescending() {
+        // testing the walking lanes with a descending order index
+        OrderedContentMirrorStoreStrategy store = new OrderedContentMirrorStoreStrategy(
+            OrderDirection.DESC);
+        NodeBuilder builder = EmptyNodeState.EMPTY_NODE.builder();
+        String n00 = KEYS[0];
+        String n01 = KEYS[1];
+        String n02 = KEYS[2];
+        String n03 = KEYS[3];
+        String n04 = KEYS[4];
+        String n05 = KEYS[5];
+        String n06 = KEYS[6];
+        String n07 = KEYS[7];
+        String n08 = KEYS[8];
+        String n09 = KEYS[9];
+        String n10 = KEYS[10];
+        String n11 = KEYS[11];
+        String n12 = KEYS[12];
+
+        // initialising the store
+        builder.child(START).setProperty(NEXT, ImmutableList.of(n12, n11, n09, n02), Type.STRINGS);
+        builder.child(n12).setProperty(NEXT,   ImmutableList.of(n11 , "",  "",  ""), Type.STRINGS);
+        builder.child(n11).setProperty(NEXT,   ImmutableList.of(n10, n09,  "",  ""), Type.STRINGS);
+        builder.child(n10).setProperty(NEXT,   ImmutableList.of(n09,  "",  "",  ""), Type.STRINGS);
+        builder.child(n09).setProperty(NEXT,   ImmutableList.of(n08, n07, n05,  ""), Type.STRINGS);
+        builder.child(n08).setProperty(NEXT,   ImmutableList.of(n07,  "",  "",  ""), Type.STRINGS);
+        builder.child(n07).setProperty(NEXT,   ImmutableList.of(n06, n05,  "",  ""), Type.STRINGS);
+        builder.child(n06).setProperty(NEXT,   ImmutableList.of(n05,  "",  "",  ""), Type.STRINGS);
+        builder.child(n05).setProperty(NEXT,   ImmutableList.of(n04, n02, n02,  ""), Type.STRINGS);
+        builder.child(n04).setProperty(NEXT,   ImmutableList.of(n03,  "",  "",  ""), Type.STRINGS);
+        builder.child(n03).setProperty(NEXT,   ImmutableList.of(n02,  "",  "",  ""), Type.STRINGS);
+        builder.child(n02).setProperty(NEXT,   ImmutableList.of(n01,  "",  "",  ""), Type.STRINGS);
+        builder.child(n01).setProperty(NEXT,   ImmutableList.of(n00,  "",  "",  ""), Type.STRINGS);
+        builder.child(n00).setProperty(NEXT,   ImmutableList.of("" ,  "",  "",  ""), Type.STRINGS);
+
+        NodeState index = builder.getNodeState();
+        
+        printSkipList(index);
+        
+        // testing the exception in case of wrong parameters
+        String searchFor = "wedontcareaswetesttheexception";
+        NodeState node = index.getChildNode(searchFor);
+        ChildNodeEntry entry = new OrderedChildNodeEntry(
+            searchFor, node);
+        ChildNodeEntry[] wl = new ChildNodeEntry[0];
+        ChildNodeEntry item = null;
+        ChildNodeEntry lane0, lane1, lane2, lane3;
+        
+        try {
+            item = store.seek(index,
+                new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+            fail("With a wrong size for the lane it should have raised an exception");
+        } catch (IllegalArgumentException e) {
+            // so far so good. It was expected
+        }
+        
+        // testing equality
+        searchFor = n12;
+        lane3 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane2 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane1 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane0 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+
+        searchFor = n08;
+        lane3 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane2 = new OrderedChildNodeEntry(n09, index.getChildNode(n09));
+        lane1 = new OrderedChildNodeEntry(n09, index.getChildNode(n09));
+        lane0 = new OrderedChildNodeEntry(n09, index.getChildNode(n09));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+
+        searchFor = n06;
+        lane3 = new OrderedChildNodeEntry(START, index.getChildNode(START));
+        lane2 = new OrderedChildNodeEntry(n09, index.getChildNode(n09));
+        lane1 = new OrderedChildNodeEntry(n07, index.getChildNode(n07));
+        lane0 = new OrderedChildNodeEntry(n07, index.getChildNode(n07));
+        entry = new OrderedChildNodeEntry(searchFor,
+            index.getChildNode(searchFor));
+        wl = new ChildNodeEntry[OrderedIndex.LANES];
+        item = store.seek(index,
+            new OrderedContentMirrorStoreStrategy.PredicateEquals(searchFor), wl);
+        assertNotNull(wl);
+        assertEquals(OrderedIndex.LANES, wl.length);
+        assertEquals("Wrong lane", lane0, wl[0]);
+        assertEquals("Wrong lane", lane1, wl[1]);
+        assertEquals("Wrong lane", lane2, wl[2]);
+        assertEquals("Wrong lane", lane3, wl[3]);
+        assertEquals("Wrong item returned", entry, item);
+    }
+        
+    /**
+     * convenience method for printing the current index as SkipList
+     * 
+     * @param index
+     */
+    private static void printSkipList(NodeState index) {
+        final String marker = "->o-";
+        final String filler = "----";
+        StringBuffer sb = new StringBuffer();
+        List<String> elements = new ArrayList<String>();
+        
+        // printing the elements
+        NodeState current = index.getChildNode(START);
+        sb.append("STR ");
+        
+        String next = getNext(current);
+        int position = 0;
+        while (!Strings.isNullOrEmpty(next)) {
+            elements.add(next);
+            current = index.getChildNode(next);
+            sb.append(String.format("%s ", next));
+            next = getNext(current);
+        }
+        sb.append("NIL");
+
+        for (int lane = 0; lane < OrderedIndex.LANES; lane++) {
+            current = index.getChildNode(START);
+            sb.append("\n |-");
+            next = getNext(current, lane);
+            position = 0;
+            while (!Strings.isNullOrEmpty(next)) {
+                int p = elements.indexOf(next);
+                // padding from position to p
+                while (position++ < p) {
+                    sb.append(filler);
+                }
+                current = index.getChildNode(next);
+                sb.append(marker);
+                next = getNext(current, lane);
+            }
+            //filling the gap towards the end
+            while (position++ < elements.size()) {
+                sb.append(filler);
+            }
+            sb.append("->|");
+        }
+
+        LOG.debug("\n{}", sb.toString());
+    }
+    
+    @Test
+    public void predicateLessThan() { 
+        Predicate<ChildNodeEntry> predicate;
+        String searchfor;
+        ChildNodeEntry entry;
+        
+        searchfor = "b";
+        predicate = new PredicateLessThan(searchfor, true);
+        entry = new OrderedChildNodeEntry("a", EmptyNodeState.EMPTY_NODE);
+        assertTrue(predicate.apply(entry));
+
+        searchfor = "a";
+        predicate = new PredicateLessThan(searchfor, true);
+        entry = new OrderedChildNodeEntry("b", EmptyNodeState.EMPTY_NODE);
+        assertFalse(predicate.apply(entry));
+
+        searchfor = "a";
+        predicate = new PredicateLessThan(searchfor, true);
+        entry = null;
+        assertFalse(predicate.apply(entry));
+    }
+
+    /**
+     * tests the pruning with a mult-value index
+     */
+    @Test
+    public void prune() {
+        MockOrderedContentMirrorStoreStrategy store = new MockOrderedContentMirrorStoreStrategy();
+        NodeBuilder index;
+        NodeBuilder node;
+        final String path0 = "/content/doc0";
+        final String path1 = "/content/doc1";
+        final String path2 = "/content/doc2";
+        final String n0 = KEYS[0];
+        final String n1 = KEYS[1];
+        final String n2 = KEYS[2];
+
+
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(0);
+        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.
+
+        // removing n2
+        store.update(index, path2, newHashSet(n2), EMPTY_KEY_SET);
+
+        node = index.getChildNode(START);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(n0, "", "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n0);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(n1, "", "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n1);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of("", "", "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n2);
+        assertFalse(node.exists());
+
+        // creating
+        // STR 000 001 002 NIL
+        //  |-->o-->o-->o-->|
+        //  |------>o-->o-->|
+        //  |---------->o-->|
+        //  |---------->o-->|
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(0);
+        store.update(index, path0, EMPTY_KEY_SET, newHashSet(n0));
+        store.setLane(1);
+        store.update(index, path1, EMPTY_KEY_SET, newHashSet(n1));
+        store.setLane(3);
+        store.update(index, path2, EMPTY_KEY_SET, newHashSet(n2));
+
+        // and after this update we should have
+        // STR 000 001 NIL
+        //  |-->o-->o-->|
+        //  |------>o-->|
+        //  |---------->|
+        //  |---------->|
+        store.update(index, path2, newHashSet(n2), EMPTY_KEY_SET);
+
+        // checking key nodes
+        node = index.getChildNode(START);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(n0, n1, "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n0);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(n1, "", "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        node = index.getChildNode(n1);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of("", "", "", ""), 
+            node.getProperty(NEXT).getValue(Type.STRINGS));
+        assertFalse(index.hasChildNode(n2));
+        
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        store.setLane(0);
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[0]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[2]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[4]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[6]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[8]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[9]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[11]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[12]));
+        store.setLane(1);
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[1]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[5]));
+        store.setLane(2);
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[3]));
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[7]));
+        store.setLane(3);
+        store.update(index, "/foo/bar", EMPTY_KEY_SET, newHashSet(KEYS[10]));
+
+        store.update(index, "/foo/bar", newHashSet(KEYS[5]), EMPTY_KEY_SET);
+
+        node = index.getChildNode(START);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[0], KEYS[1], KEYS[3], KEYS[10]),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[0]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[1], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[1]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[2], KEYS[3], "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[2]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[3], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[3]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[4], KEYS[7], KEYS[7], ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[4]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[6], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[6]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[7], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[7]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[8], KEYS[10], KEYS[10], ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[8]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[9], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[9]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[10], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[10]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[11], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[11]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of(KEYS[12], "", "", ""),
+            getMultiNext(node.getNodeState()));
+        node = index.getChildNode(KEYS[12]);
+        assertTrue(node.exists());
+        assertEquals(ImmutableList.of("", "", "", ""),
+            getMultiNext(node.getNodeState()));
+        assertFalse(node.getChildNode(KEYS[5]).exists());
+    }
+    
+    /**
+     * tests the query aspect of an item that falls int he middle of two lane jumps
+     */
+    @Test
+    public void queryMiddleItem() {
+        MockOrderedContentMirrorStoreStrategy ascending = new MockOrderedContentMirrorStoreStrategy(
+            OrderDirection.ASC);
+        MockOrderedContentMirrorStoreStrategy descending = new MockOrderedContentMirrorStoreStrategy(
+            OrderDirection.DESC);
+        NodeBuilder index;
+        final String propertyName = "property";
+        Iterator<String> resultset;
+        FilterImpl filter;
+        NodeBuilder indexMeta;        
+        
+        /* generating
+         * 
+         * STR 000 001 002 003 004 005 NIL
+         *  |-->o-->o-->o-->o-->o-->o-->|
+         *  |------>o------>o---------->|
+         *  |-------------->o---------->|
+         *  |-------------------------->|
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        ascending.setLane(0);
+        ascending.update(index, "/path/a", EMPTY_KEY_SET, newHashSet(KEYS[0]));
+        ascending.setLane(1);
+        ascending.update(index, "/path/b", EMPTY_KEY_SET, newHashSet(KEYS[1]));
+        ascending.setLane(0);
+        ascending.update(index, "/path/c", EMPTY_KEY_SET, newHashSet(KEYS[2]));
+        ascending.setLane(2);
+        ascending.update(index, "/path/d", EMPTY_KEY_SET, newHashSet(KEYS[3]));
+        ascending.setLane(0);
+        ascending.update(index, "/path/e", EMPTY_KEY_SET, newHashSet(KEYS[4]));
+        ascending.update(index, "/path/f", EMPTY_KEY_SET, newHashSet(KEYS[5]));
+
+        printSkipList(index.getNodeState());
+        
+        indexMeta = EmptyNodeState.EMPTY_NODE.builder();
+        indexMeta.setChildNode(IndexConstants.INDEX_CONTENT_NODE_NAME, index.getNodeState());
+
+        // querying >= 002
+        filter = new FilterImpl();
+        filter.restrictProperty(propertyName, Operator.GREATER_OR_EQUAL,
+            PropertyValues.newString(KEYS[2]));
+
+        resultset = ascending.query(filter, "indexName", indexMeta.getNodeState(),
+            filter.getPropertyRestriction(propertyName)).iterator();
+        
+        assertEquals("path/c", resultset.next());
+        assertEquals("path/d", resultset.next());
+        assertEquals("path/e", resultset.next());
+        assertEquals("path/f", resultset.next());
+        assertFalse("We should have not any results left", resultset.hasNext());
+        
+        //querying <= 002
+        filter = new FilterImpl();
+        filter.restrictProperty(propertyName, Operator.LESS_OR_EQUAL,
+            PropertyValues.newString(KEYS[2]));
+        
+        resultset = ascending.query(filter, "indexName", indexMeta.getNodeState(),
+            filter.getPropertyRestriction(propertyName)).iterator();
+
+        assertEquals("path/a", resultset.next());
+        assertEquals("path/b", resultset.next());
+        assertEquals("path/c", resultset.next());
+        assertFalse("We should have not any results left", resultset.hasNext());
+        
+        /*
+         * generating
+         * 
+         * STR 005 004 003 002 001 000 NIL
+         *  |-->o-->o-->o-->o-->o-->o-->|
+         *  |------>o------>o---------->|
+         *  |-------------->o---------->|
+         *  |-------------------------->|
+         */
+        index = EmptyNodeState.EMPTY_NODE.builder();
+        descending.setLane(0);
+        descending.update(index, "/path/a", EMPTY_KEY_SET, newHashSet(KEYS[5]));
+        descending.setLane(1);
+        descending.update(index, "/path/b", EMPTY_KEY_SET, newHashSet(KEYS[4]));
+        descending.setLane(0);
+        descending.update(index, "/path/c", EMPTY_KEY_SET, newHashSet(KEYS[3]));
+        descending.setLane(2);
+        descending.update(index, "/path/d", EMPTY_KEY_SET, newHashSet(KEYS[2]));
+        descending.setLane(0);
+        descending.update(index, "/path/e", EMPTY_KEY_SET, newHashSet(KEYS[1]));
+        descending.update(index, "/path/f", EMPTY_KEY_SET, newHashSet(KEYS[0]));
+        
+        printSkipList(index.getNodeState());
+        
+        indexMeta = EmptyNodeState.EMPTY_NODE.builder();
+        indexMeta.setChildNode(IndexConstants.INDEX_CONTENT_NODE_NAME, index.getNodeState());
+        
+        // querying >= 003
+        filter = new FilterImpl();
+        filter.restrictProperty(propertyName, Operator.GREATER_OR_EQUAL,
+            PropertyValues.newString(KEYS[3]));
+
+        resultset = descending.query(filter, "indexName", indexMeta.getNodeState(),
+            filter.getPropertyRestriction(propertyName)).iterator();
+
+        assertEquals("path/a", resultset.next());
+        assertEquals("path/b", resultset.next());
+        assertEquals("path/c", resultset.next());
+        assertFalse("We should have not any results left", resultset.hasNext());
+
+        // querying <= 003
+        filter = new FilterImpl();
+        filter.restrictProperty(propertyName, Operator.LESS_OR_EQUAL,
+            PropertyValues.newString(KEYS[3]));
+
+        resultset = descending.query(filter, "indexName", indexMeta.getNodeState(),
+            filter.getPropertyRestriction(propertyName)).iterator();
+
+        assertEquals("path/c", resultset.next());
+        assertEquals("path/d", resultset.next());
+        assertEquals("path/e", resultset.next());
+        assertEquals("path/f", resultset.next());
+        assertFalse("We should have not any results left", resultset.hasNext());
+    }
 }
diff --git a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OrderedIndexConcurrentClusterIT.java b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OrderedIndexConcurrentClusterIT.java
index 5aaea14..7f3f777 100644
--- a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OrderedIndexConcurrentClusterIT.java
+++ b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OrderedIndexConcurrentClusterIT.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import javax.jcr.Credentials;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
 import javax.jcr.PropertyType;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
@@ -43,7 +44,6 @@ import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,6 +52,7 @@ public class OrderedIndexConcurrentClusterIT {
     private static final Logger LOG = LoggerFactory.getLogger(OrderedIndexConcurrentClusterIT.class);
     
     private static final int NUM_CLUSTER_NODES = 5;
+    private static final int LOOP = 2800;
     private static final int COUNT = 5;
     private static final Credentials ADMIN = new SimpleCredentials("admin", "admin".toCharArray());
     private static final String INDEX_NODE_NAME = "lastModified";
@@ -174,7 +175,14 @@ public class OrderedIndexConcurrentClusterIT {
                              Map<String, Exception> exceptions)
             throws RepositoryException {
 
-        Node root = session.getRootNode().getNode(nodeName);
+        Node root;
+        try {
+            root = session.getRootNode().getNode(nodeName);
+        } catch (PathNotFoundException e) {
+            LOG.error("Not found. {}", nodeName);
+            throw e;
+        }
+        
         NodeIterator children = root.getNodes();
         
         while (children.hasNext()) {
@@ -183,7 +191,7 @@ public class OrderedIndexConcurrentClusterIT {
             while (children2.hasNext()) {
                 children2.nextNode().remove();
             }
-            LOG.debug("deleting {}", node.getName());
+            LOG.debug("deleting /{}/{}", nodeName, node.getName());
             node.remove();
             session.save();
         }
@@ -202,10 +210,9 @@ public class OrderedIndexConcurrentClusterIT {
         }
     }
 
-    @Ignore("OAK-1717")
     @Test
     public void deleteConcurrently() throws Exception {
-        final int loop = 120;
+        final int loop = LOOP;
         final int count = COUNT;
         final int clusters = NUM_CLUSTER_NODES;
 
@@ -251,6 +258,11 @@ public class OrderedIndexConcurrentClusterIT {
         session.save();
         
         if (exceptions.isEmpty()) {
+            // ensuring the cluster is aligned before triggering in order to avoid any
+            // PathNotFoundException
+            for (DocumentMK mk : mks) {
+                mk.getNodeStore().runBackgroundOperations();
+            }
             for (Thread t : workers) {
                 t.start();
             }
-- 
1.8.5.2 (Apple Git-48)

