You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2013/07/15 15:56:44 UTC

svn commit: r1503251 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/index/ main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/ main/java/org/apache/jackrabbit/oak/plugins/index/property/ main/java/org/apach...

Author: thomasm
Date: Mon Jul 15 13:56:43 2013
New Revision: 1503251

URL: http://svn.apache.org/r1503251
Log:
OAK-894 Query: better cost estimates for indexes (workaround)

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java Mon Jul 15 13:56:43 2013
@@ -32,6 +32,8 @@ public interface IndexConstants {
     String REINDEX_PROPERTY_NAME = "reindex";
 
     String ASYNC_PROPERTY_NAME = "async";
+    
+    String ENTRY_COUNT_PROPERTY_NAME = "entryCount";
 
     /**
      * Marks a unique property index.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java Mon Jul 15 13:56:43 2013
@@ -61,7 +61,7 @@ public class IndexUtils {
     }
 
     /**
-     * Create a new property2 index definition below the given {@code indexNode}.
+     * Create a new property index definition below the given {@code indexNode}.
      *
      * @param index         The oak:index node builder
      * @param indexDefName  The name of the new property index.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java Mon Jul 15 13:56:43 2013
@@ -19,7 +19,6 @@
 package org.apache.jackrabbit.oak.plugins.index.nodetype;
 
 import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexLookup;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Cursors;
 import org.apache.jackrabbit.oak.spi.query.Filter;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java Mon Jul 15 13:56:43 2013
@@ -75,7 +75,6 @@ class NodeTypeIndexLookup implements Jcr
      * Returns the paths that match the given node types.
      *
      * @param filter the filter (used for logging)
-     * @param nodeTypes the names of the node types to match.
      * @return the matched paths (the result might contain duplicate entries)
      */
     public Iterable<String> query(Filter filter) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexEditor.java Mon Jul 15 13:56:43 2013
@@ -227,14 +227,14 @@ class PropertyIndexEditor implements Ind
 
         if (parent == null) {
             // make sure that the index node exist, even with no content
-            NodeBuilder index = definition.child(INDEX_CONTENT_NODE_NAME);
+            definition.child(INDEX_CONTENT_NODE_NAME);
 
             // check uniqueness constraints when leaving the root
             if (keysToCheckForUniqueness != null
                     && !keysToCheckForUniqueness.isEmpty()) {
-                NodeState state = index.getNodeState();
+                NodeState indexMeta = definition.getNodeState();
                 for (String key : keysToCheckForUniqueness) {
-                    if (STORE.count(state, singleton(key), 2) > 1) {
+                    if (STORE.count(indexMeta, singleton(key), 2) > 1) {
                         throw new CommitFailedException(
                                 CONSTRAINT, 30,
                                 "Uniqueness constraint violated for key " + key);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexLookup.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexLookup.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexLookup.java Mon Jul 15 13:56:43 2013
@@ -24,7 +24,6 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider.TYPE;
 import static org.apache.jackrabbit.oak.plugins.index.property.PropertyIndex.encode;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
 
 import java.util.Iterator;
 import java.util.Set;
@@ -80,19 +79,14 @@ public class PropertyIndexLookup {
      * @return true if the property is indexed
      */
     public boolean isIndexed(String propertyName, String path, Filter filter) {
-        Set<String> supertypes = null;
-        if (filter != null && !filter.matchesAllTypes()) {
-            supertypes = filter.getSupertypes();
-        }
-
         if (PathUtils.denotesRoot(path)) {
-            return getIndexDataNode(root, propertyName, supertypes).exists();
+            return getIndexNode(root, propertyName, filter) != null;
         }
 
         NodeState node = root;
         Iterator<String> it = PathUtils.elements(path).iterator();
         while (it.hasNext()) {
-            if (getIndexDataNode(node, propertyName, supertypes).exists()) {
+            if (getIndexNode(node, propertyName, filter) != null) {
                 return true;
             }
             node = node.getChildNode(it.next());
@@ -101,61 +95,55 @@ public class PropertyIndexLookup {
     }
 
     public Iterable<String> query(Filter filter, String propertyName, PropertyValue value) {
-        Set<String> supertypes = null;
-        if (filter != null && !filter.matchesAllTypes()) {
-            supertypes = filter.getSupertypes();
-        }
-
-        NodeState state = getIndexDataNode(root, propertyName, supertypes);
-        if (state.exists()) {
-            return store.query(filter, propertyName, state, encode(value));
-        } else {
+        NodeState indexMeta = getIndexNode(root, propertyName, filter);
+        if (indexMeta == null) {
             throw new IllegalArgumentException("No index for " + propertyName);
         }
+        return store.query(filter, propertyName, indexMeta, encode(value));
     }
 
-    public double getCost(Filter filter, String name, PropertyValue value) {
-        Set<String> supertypes = null;
-        if (filter != null && !filter.matchesAllTypes()) {
-            supertypes = filter.getSupertypes();
-        }
-
-        NodeState state = getIndexDataNode(root, name, supertypes);
-        if (state.exists()) {
-            return store.count(state, encode(value), MAX_COST);
-        } else {
+    public double getCost(Filter filter, String propertyName, PropertyValue value) {
+        NodeState indexMeta = getIndexNode(root, propertyName, filter);
+        if (indexMeta == null) {
             return Double.POSITIVE_INFINITY;
         }
+        return store.count(indexMeta, encode(value), MAX_COST);
     }
 
     /**
-     * Get the node with the index data for the given property, if there is an
-     * applicable index with data.
+     * Get the node with the index definition for the given property, if there
+     * is an applicable index with data.
      * 
      * @param propertyName the property name
-     * @param supertypes the filter node type and all its supertypes,
-     *                   or {@code null} if the filter matches all types
-     * @return the node where the index data is stored, or null if no index
-     *         definition or index data node was found
+     * @param filter the filter (which contains information of all supertypes,
+     *            unless the filter matches all types)
+     * @return the node where the index definition (metadata) is stored (the
+     *         parent of ":index"), or null if no index definition or index data
+     *         node was found
      */
     @Nullable
-    private static NodeState getIndexDataNode(
-            NodeState node, String propertyName, Set<String> supertypes) {
-        //keep a fallback to a matching index def that has *no* node type constraints
-        NodeState fallback = MISSING_NODE;
+    private static NodeState getIndexNode(
+            NodeState node, String propertyName, Filter filter) {
+        // keep a fallback to a matching index def that has *no* node type constraints
+        // (initially, there is no fallback)
+        NodeState fallback = null;
 
         NodeState state = node.getChildNode(INDEX_DEFINITIONS_NAME);
         for (ChildNodeEntry entry : state.getChildNodeEntries()) {
-            NodeState ns = entry.getNodeState();
-            PropertyState type = ns.getProperty(TYPE_PROPERTY_NAME);
+            NodeState index = entry.getNodeState();
+            PropertyState type = index.getProperty(TYPE_PROPERTY_NAME);
             if (type == null || type.isArray() || !TYPE.equals(type.getValue(Type.STRING))) {
                 continue;
             }
-            if (contains(ns.getNames(PROPERTY_NAMES), propertyName)) {
-                NodeState index = ns.getChildNode(INDEX_CONTENT_NODE_NAME);
-                if (ns.hasProperty(DECLARING_NODE_TYPES)) {
+            if (contains(index.getNames(PROPERTY_NAMES), propertyName)) {
+                NodeState indexContent = index.getChildNode(INDEX_CONTENT_NODE_NAME);
+                if (!indexContent.exists()) {
+                    continue;
+                }
+                Set<String> supertypes = getSuperTypes(filter);
+                if (index.hasProperty(DECLARING_NODE_TYPES)) {
                     if (supertypes != null) {
-                        for (String typeName : ns.getNames(DECLARING_NODE_TYPES)) {
+                        for (String typeName : index.getNames(DECLARING_NODE_TYPES)) {
                             if (supertypes.contains(typeName)) {
                                 // TODO: prefer the most specific type restriction
                                 return index;
@@ -164,12 +152,20 @@ public class PropertyIndexLookup {
                     }
                 } else if (supertypes == null) {
                     return index;
-                } else if (index.exists() && !fallback.exists()) {
+                } else if (fallback == null) {
+                    // update the fallback
                     fallback = index;
                 }
             }
         }
         return fallback;
     }
+    
+    private static Set<String> getSuperTypes(Filter filter) {
+        if (filter != null && !filter.matchesAllTypes()) {
+            return filter.getSupertypes();
+        }
+        return null;
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java Mon Jul 15 13:56:43 2013
@@ -17,11 +17,15 @@
 package org.apache.jackrabbit.oak.plugins.index.property.strategy;
 
 import static com.google.common.collect.Queues.newArrayDeque;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ENTRY_COUNT_PROPERTY_NAME;
 
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.Set;
 
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -113,7 +117,8 @@ public class ContentMirrorStoreStrategy 
 
     @Override
     public Iterable<String> query(final Filter filter, final String indexName, 
-            final NodeState index, final Iterable<String> values) {
+            final NodeState indexMeta, final Iterable<String> values) {
+        final NodeState index = indexMeta.getChildNode(INDEX_CONTENT_NODE_NAME);
         return new Iterable<String>() {
             @Override
             public Iterator<String> iterator() {
@@ -137,9 +142,14 @@ public class ContentMirrorStoreStrategy 
     }
 
     @Override
-    public int count(NodeState index, Set<String> values, int max) {
+    public long count(NodeState indexMeta, Set<String> values, int max) {
+        NodeState index = indexMeta.getChildNode(INDEX_CONTENT_NODE_NAME);
         int count = 0;
         if (values == null) {
+            PropertyState ec = indexMeta.getProperty(ENTRY_COUNT_PROPERTY_NAME);
+            if (ec != null) {
+                return ec.getValue(Type.LONG);
+            }
             CountingNodeVisitor v = new CountingNodeVisitor(max);
             v.visit(index);
             count = v.getEstimatedCount();

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java Mon Jul 15 13:56:43 2013
@@ -45,21 +45,21 @@ public interface IndexStoreStrategy {
      * 
      * @param filter the filter (used for logging)
      * @param indexName the name of the index (for logging)
-     * @param index index node (may not be null)
+     * @param indexMeta the index metadata node (may not be null)
      * @param values values to look for (null to check for property existence)
      * @return an iterator of paths
      */
-    Iterable<String> query(Filter filter, String indexName, NodeState index, Iterable<String> values);
+    Iterable<String> query(Filter filter, String indexName, NodeState indexMeta, Iterable<String> values);
 
     /**
      * Count the occurrence of a given set of values. Used in calculating the
      * cost of an index.
      * 
-     * @param index the index node (may not be null)
+     * @param indexMeta the index metadata node (may not be null)
      * @param values values to look for (null to check for property existence)
      * @param max the maximum value to return
      * @return the aggregated count of occurrences for each provided value
      */
-    int count(NodeState index, Set<String> values, int max);
+    long count(NodeState indexMeta, Set<String> values, int max);
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java Mon Jul 15 13:56:43 2013
@@ -66,8 +66,11 @@ public class InitialContent implements R
 
             IndexUtils.createIndexDefinition(index, "uuid", true, true,
                     ImmutableList.<String>of(JCR_UUID), null);
-            IndexUtils.createIndexDefinition(index, "nodetype", true, false,
+            NodeBuilder nt = 
+                    IndexUtils.createIndexDefinition(index, "nodetype", true, false,
                     ImmutableList.of(JCR_PRIMARYTYPE, JCR_MIXINTYPES), null);
+            // the cost of using the property index for "@primaryType is not null" is very high
+            nt.setProperty(IndexConstants.ENTRY_COUNT_PROPERTY_NAME, Long.valueOf(Long.MAX_VALUE));
         }
         NodeStore store = new MemoryNodeStore();
         NodeStoreBranch branch = store.branch();

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java?rev=1503251&r1=1503250&r2=1503251&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java Mon Jul 15 13:56:43 2013
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.collect.Sets.newHashSet;
 import static java.util.Arrays.asList;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
 import java.util.Collections;
@@ -25,18 +26,19 @@ import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy;
-import org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.junit.Assert;
 import org.junit.Test;
 
+/**
+ * Test the content mirror strategy
+ */
 public class ContentMirrorStoreStrategyTest {
 
-    private static final Set<String> empty = newHashSet();
+    private static final Set<String> EMPTY = newHashSet();
 
-    private static final Set<String> key = newHashSet("key");
+    private static final Set<String> KEY = newHashSet("key");
 
     /**
      * <p>
@@ -53,14 +55,14 @@ public class ContentMirrorStoreStrategyT
      * </ul>
      */
     @Test
-    public void testIndexPruning() throws Exception {
+    public void testIndexPruning() {
         IndexStoreStrategy store = new ContentMirrorStoreStrategy();
 
         NodeState root = EMPTY_NODE;
         NodeBuilder index = root.builder();
 
         for (String path : asList("/", "a/b/c", "a/b/d", "b", "d/e", "d/e/f")) {
-            store.update(index, path, empty, key);
+            store.update(index, path, EMPTY, KEY);
         }
         checkPath(index, "key", "", true);
         checkPath(index, "key", "a/b/c", true);
@@ -71,34 +73,34 @@ public class ContentMirrorStoreStrategyT
 
         // remove the root key, removes just the "match" property, when the
         // index is not empty
-        store.update(index, "/", key, empty);
+        store.update(index, "/", KEY, EMPTY);
         checkPath(index, "key", "d/e/f", true);
 
         // removing intermediary path doesn't remove the entire subtree
-        store.update(index, "d/e", key, empty);
+        store.update(index, "d/e", KEY, EMPTY);
         checkPath(index, "key", "d/e/f", true);
 
         // removing intermediary path doesn't remove the entire subtree
-        store.update(index, "d/e/f", key, empty);
+        store.update(index, "d/e/f", KEY, EMPTY);
         checkNotPath(index, "key", "d");
 
         // brother segment removed
-        store.update(index, "a/b/d", key, empty);
-        store.update(index, "a/b", key, empty);
+        store.update(index, "a/b/d", KEY, EMPTY);
+        store.update(index, "a/b", KEY, EMPTY);
         checkPath(index, "key", "a/b/c", true);
 
         // reinsert root and remove everything else
-        store.update(index, "", empty, key);
-        store.update(index, "d/e/f", key, empty);
-        store.update(index, "b", key, empty);
-        store.update(index, "a/b/c", key, empty);
+        store.update(index, "", EMPTY, KEY);
+        store.update(index, "d/e/f", KEY, EMPTY);
+        store.update(index, "b", KEY, EMPTY);
+        store.update(index, "a/b/c", KEY, EMPTY);
 
         // remove the root key when the index is empty
-        store.update(index, "", key, empty);
+        store.update(index, "", KEY, EMPTY);
         Assert.assertEquals(0, index.getChildNodeCount());
     }
 
-    private void checkPath(NodeBuilder node, String key, String path,
+    private static void checkPath(NodeBuilder node, String key, String path,
             boolean checkMatch) {
         path = PathUtils.concat(key, path);
         NodeBuilder check = node;
@@ -112,7 +114,7 @@ public class ContentMirrorStoreStrategyT
         }
     }
 
-    private void checkNotPath(NodeBuilder node, String key, String path) {
+    private static void checkNotPath(NodeBuilder node, String key, String path) {
         path = PathUtils.concat(key, path);
         String parentPath = PathUtils.getParentPath(path);
         String name = PathUtils.getName(path);
@@ -129,12 +131,13 @@ public class ContentMirrorStoreStrategyT
     public void testUnique() throws CommitFailedException {
         IndexStoreStrategy store = new ContentMirrorStoreStrategy();
         NodeState root = EMPTY_NODE;
-        NodeBuilder index = root.builder();
-        store.update(index, "a", empty, key);
-        store.update(index, "b", empty, key);
+        NodeBuilder indexMeta = root.builder();
+        NodeBuilder index = indexMeta.child(INDEX_CONTENT_NODE_NAME);        
+        store.update(index, "a", EMPTY, KEY);
+        store.update(index, "b", EMPTY, KEY);
         Assert.assertTrue(
                 "ContentMirrorStoreStrategy should guarantee uniqueness on insert",
-                store.count(index.getNodeState(), Collections.singleton("key"), 2) > 1);
+                store.count(indexMeta.getNodeState(), Collections.singleton("key"), 2) > 1);
     }
 
 }