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 ju...@apache.org on 2012/10/04 11:04:29 UTC

svn commit: r1393963 - in /jackrabbit/oak/trunk: oak-core/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/propert...

Author: jukka
Date: Thu Oct  4 09:04:28 2012
New Revision: 1393963

URL: http://svn.apache.org/viewvc?rev=1393963&view=rev
Log:
OAK-270: Enforce uniqueness of jcr:uuid

Generalize the unique index to a full property index that can optionally also enforce uniqueness constraints.

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexUpdate.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexTest.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/unique/UniqueIndexValidator.java
Modified:
    jackrabbit/oak/trunk/oak-core/pom.xml
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PropertyIndexer.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/InitialContent.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java

Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Thu Oct  4 09:04:28 2012
@@ -48,7 +48,7 @@
               org.apache.jackrabbit.oak.plugins.identifier,
               org.apache.jackrabbit.oak.plugins.name,
               org.apache.jackrabbit.oak.plugins.type,
-              org.apache.jackrabbit.oak.plugins.unique,
+              org.apache.jackrabbit.oak.plugins.property,
               org.apache.jackrabbit.oak.plugins.commit,
               org.apache.jackrabbit.oak.plugins.lucene,
               org.apache.jackrabbit.oak.spi.query,

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PropertyIndexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PropertyIndexer.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PropertyIndexer.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PropertyIndexer.java Thu Oct  4 09:04:28 2012
@@ -22,7 +22,6 @@ import java.util.List;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.plugins.unique.UniqueIndex;
 import org.apache.jackrabbit.oak.query.index.PrefixContentIndex;
 import org.apache.jackrabbit.oak.query.index.PropertyContentIndex;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
@@ -80,7 +79,6 @@ public class PropertyIndexer implements 
                 }
             }
         }
-        queryIndexList.add(new UniqueIndex());
         return queryIndexList;
     }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java Thu Oct  4 09:04:28 2012
@@ -304,6 +304,21 @@ public class MemoryNodeBuilder implement
     }
 
     @Override @Nonnull
+    public NodeBuilder set(@Nonnull String name, @Nonnull String value) {
+        return setProperty(name, new StringValue(value));
+    }
+
+    @Override @Nonnull
+    public NodeBuilder set(
+            @Nonnull String name, @Nonnull String... values) {
+        List<CoreValue> list = Lists.newArrayListWithCapacity(values.length);
+        for (String value : values) {
+            list.add(new StringValue(value));
+        }
+        return setProperty(name, list);
+    }
+
+    @Override @Nonnull
     public NodeBuilder removeProperty(String name) {
         MutableNodeState mstate = write();
 

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndex.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndex.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndex.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.query.index.IndexRowImpl;
+import org.apache.jackrabbit.oak.query.index.TraversingCursor;
+import org.apache.jackrabbit.oak.spi.query.Cursor;
+import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.query.IndexRow;
+import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Sets;
+
+public class PropertyIndex implements QueryIndex {
+
+    private static final int MAX_STRING_LENGTH = 100; // TODO: configurable
+
+    static String encode(CoreValue value) {
+        try {
+            String string = value.getString();
+            if (string.length() > MAX_STRING_LENGTH) {
+                string.substring(0, MAX_STRING_LENGTH);
+            }
+            return URLEncoder.encode(string, Charsets.UTF_8.name());
+        } catch (UnsupportedEncodingException e) {
+           throw new IllegalStateException("UTF-8 is unsupported", e);
+        }
+    }
+
+
+    //--------------------------------------------------------< QueryIndex >--
+
+    @Override
+    public String getIndexName() {
+        return "oak:index";
+    }
+
+    @Override
+    public double getCost(Filter filter) {
+        return 1.0; // FIXME: proper cost calculation
+    }
+
+    @Override
+    public Cursor query(Filter filter, NodeState root) {
+        Set<String> paths = null;
+
+        PropertyIndexLookup lookup = new PropertyIndexLookup(root);
+        for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+            if (pr.firstIncluding && pr.lastIncluding
+                    && pr.first.equals(pr.last) // TODO: range queries
+                    && lookup.isIndexed(pr.propertyName, "/")) { // TODO: path
+                Set<String> set = lookup.find(pr.propertyName, pr.first);
+                if (paths == null) {
+                    paths = Sets.newHashSet(set);
+                } else {
+                    paths.retainAll(set);
+                }
+            }
+        }
+
+        if (paths != null) {
+            return new PathCursor(paths);
+        } else {
+            return new TraversingCursor(filter, root);
+        }
+    }
+
+    @Override
+    public String getPlan(Filter filter, NodeState root) {
+        return "oak:index"; // TODO: better plans
+    }
+
+    private static class PathCursor implements Cursor {
+
+        private final Iterator<String> iterator;
+
+        private String path;
+
+        public PathCursor(Collection<String> paths) {
+            this.iterator = paths.iterator();
+        }
+
+        @Override
+        public boolean next() {
+            if (iterator.hasNext()) {
+                path = iterator.next();
+                return true;
+            } else {
+                path = null;
+                return false;
+            }
+        }
+
+        @Override
+        public IndexRow currentRow() {
+            // TODO support jcr:score and possibly rep:exceprt
+            return new IndexRowImpl(path);
+        }
+
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexDiff.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexDiff.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexDiff.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+class PropertyIndexDiff implements NodeStateDiff {
+
+    private final PropertyIndexDiff parent;
+
+    private final NodeBuilder node;
+
+    private final String name;
+
+    private String path;
+
+    private final Map<String, List<PropertyIndexUpdate>> updates;
+
+    private PropertyIndexDiff(
+            PropertyIndexDiff parent,
+            NodeBuilder node, String name, String path,
+            Map<String, List<PropertyIndexUpdate>> updates) {
+        this.parent = parent;
+        this.node = node;
+        this.name = name;
+        this.path = path;
+        this.updates = updates;
+
+        if (node != null && node.hasChildNode("oak:index")) {
+            NodeBuilder index = node.getChildBuilder("oak:index");
+            for (String indexName : index.getChildNodeNames()) {
+                List<PropertyIndexUpdate> list = updates.get(indexName);
+                if (list == null) {
+                    list = Lists.newArrayList();
+                    updates.put(indexName, list);
+                }
+                list.add(new PropertyIndexUpdate(
+                        getPath(), index.getChildBuilder(indexName)));
+            }
+        }
+    }
+
+    public PropertyIndexDiff(
+            NodeBuilder root, Map<String, List<PropertyIndexUpdate>> updates) {
+        this(null, root, null, "/", updates);
+    }
+
+    public PropertyIndexDiff(PropertyIndexDiff parent, String name) {
+        this(parent, getChildNode(parent.node, name),
+                name, null, parent.updates);
+    }
+
+    private static NodeBuilder getChildNode(NodeBuilder node, String name) {
+        if (node != null && node.hasChildNode(name)) {
+            return node.getChildBuilder(name);
+        } else {
+            return null;
+        }
+    }
+
+    private String getPath() {
+        if (path == null) { // => parent != null
+            String parentPath = parent.getPath();
+            if ("/".equals(parentPath)) {
+                path = parentPath + name;
+            } else {
+                path = parentPath + "/" + name;
+            }
+        }
+        return path;
+    }
+
+    private Iterable<PropertyIndexUpdate> getIndexes(String name) {
+        List<PropertyIndexUpdate> indexes = updates.get(name);
+        if (indexes != null) {
+            return indexes;
+        } else {
+            return ImmutableList.of();
+        }
+    }
+
+    //-----------------------------------------------------< NodeStateDiff >--
+
+    @Override
+    public void propertyAdded(PropertyState after) {
+        for (PropertyIndexUpdate update : getIndexes(after.getName())) {
+            update.insert(getPath(), after.getValues());
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        for (PropertyIndexUpdate update : getIndexes(after.getName())) {
+            update.remove(getPath(), before.getValues());
+            update.insert(getPath(), after.getValues());
+        }
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before) {
+        for (PropertyIndexUpdate update : getIndexes(before.getName())) {
+            update.remove(getPath(), before.getValues());
+        }
+    }
+
+    @Override
+    public void childNodeAdded(String name, NodeState after) {
+        childNodeChanged(name, MemoryNodeState.EMPTY_NODE, after);
+    }
+
+    @Override
+    public void childNodeChanged(
+            String name, NodeState before, NodeState after) {
+        if (!NodeStateUtils.isHidden(name)) {
+            PropertyIndexDiff child = new PropertyIndexDiff(this, name);
+            after.compareAgainstBaseState(before, child);
+        }
+    }
+
+    @Override
+    public void childNodeDeleted(String name, NodeState before) {
+        childNodeChanged(name, before, MemoryNodeState.EMPTY_NODE);
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexHook.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexHook.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexHook.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.collect.Maps;
+
+public class PropertyIndexHook implements CommitHook {
+
+    @Override @Nonnull
+    public NodeState processCommit(NodeState before, NodeState after)
+            throws CommitFailedException {
+        NodeBuilder builder = after.getBuilder();
+
+        Map<String, List<PropertyIndexUpdate>> indexes = Maps.newHashMap();
+        PropertyIndexDiff diff = new PropertyIndexDiff(builder, indexes);
+        after.compareAgainstBaseState(before, diff);
+
+        for (List<PropertyIndexUpdate> updates : indexes.values()) {
+            for (PropertyIndexUpdate update : updates) {
+                update.apply();
+            }
+        }
+
+        return builder.getNodeState();
+    }
+
+
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexLookup.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexLookup.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexLookup.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.StringValue;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import com.google.common.collect.Sets;
+
+public class PropertyIndexLookup {
+
+    private final NodeState root;
+
+    public PropertyIndexLookup(NodeState root) {
+        this.root = root;
+    }
+
+    /**
+     * Checks whether the named properties are indexed somewhere
+     * along the given path.
+     *
+     * @param name property name
+     * @param path lookup path
+     */
+    public boolean isIndexed(String name, String path) {
+        NodeState state = root.getChildNode("oak:index");
+        if (state != null) {
+            state = state.getChildNode(name);
+            if (state != null) {
+                return true;
+            }
+        }
+
+        if (path.startsWith("/")) {
+            path = path.substring(1);
+        }
+        int slash = path.indexOf('/');
+        if (slash == -1) {
+            return false;
+        }
+
+        NodeState child = root.getChildNode(path.substring(0, slash));
+        return new PropertyIndexLookup(child).isIndexed(
+                name, path.substring(slash));
+    }
+
+    public Set<String> find(String name, String value) {
+        return find(name, new StringValue(value));
+    }
+
+    public Set<String> find(String name, CoreValue value) {
+        Set<String> paths = Sets.newHashSet();
+
+        PropertyState property = null;
+        NodeState state = root.getChildNode("oak:index");
+        if (state != null) {
+            state = state.getChildNode(name);
+            if (state != null) {
+                state = state.getChildNode(":index");
+                if (state != null) {
+                    property = state.getProperty(PropertyIndex.encode(value));
+                }
+            }
+        }
+
+        if (property != null) {
+            // We have an index for this property, so use it
+            for (CoreValue path : property.getValues()) {
+                paths.add(path.getString());
+            }
+        } else {
+            // No index available, so first check this node for a match
+            property = root.getProperty(name);
+            if (property != null) {
+                for (CoreValue cv : property.getValues()) {
+                    if (cv.equals(value)) {
+                        paths.add("");
+                        break;
+                    }
+                }
+            }
+
+            // ... and then recursively look up from the rest of the tree
+            for (ChildNodeEntry entry : root.getChildNodeEntries()) {
+                String base = entry.getName();
+                PropertyIndexLookup lookup =
+                        new PropertyIndexLookup(entry.getNodeState());
+                for (String path : lookup.find(name, value)) {
+                    if (path.isEmpty()) {
+                        paths.add(base);
+                    } else {
+                        paths.add(base + "/" + path);
+                    }
+                }
+            }
+        }
+
+        return paths;
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexProvider.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexProvider.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A provider for property indexes.
+ */
+public class PropertyIndexProvider implements QueryIndexProvider {
+
+    @Override @Nonnull
+    public List<QueryIndex> getQueryIndexes(NodeStore store) {
+        return ImmutableList.<QueryIndex>of(new PropertyIndex());
+    }
+}

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexUpdate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexUpdate.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexUpdate.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexUpdate.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.StringValue;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+class PropertyIndexUpdate {
+
+    private final String path;
+
+    private final NodeBuilder node;
+
+    private final Map<String, Set<String>> insert;
+
+    private final Map<String, Set<String>> remove;
+
+    public PropertyIndexUpdate(String path, NodeBuilder node) {
+        this.path = path;
+        this.node = node;
+        this.insert = Maps.newHashMap();
+        this.remove = Maps.newHashMap();
+    }
+
+    public void insert(String path, Iterable<CoreValue> values) {
+        Preconditions.checkArgument(path.startsWith(this.path));
+        putValues(insert, path.substring(this.path.length()), values);
+    }
+
+    public void remove(String path, Iterable<CoreValue> values) {
+        Preconditions.checkArgument(path.startsWith(this.path));
+        putValues(remove, path.substring(this.path.length()), values);
+    }
+
+    private void putValues(
+            Map<String, Set<String>> map,
+            String path, Iterable<CoreValue> values) {
+        for (CoreValue value : values) {
+            if (value.getType() != PropertyType.BINARY) {
+                String key = PropertyIndex.encode(value);
+                Set<String> paths = map.get(key);
+                if (paths == null) {
+                    paths = Sets.newHashSet();
+                    map.put(key, paths);
+                }
+                paths.add(path);
+            }
+        }
+    }
+
+
+    public void apply() throws CommitFailedException {
+        boolean unique = node.getProperty("unique") != null;
+        NodeBuilder index = node.getChildBuilder(":index");
+
+        for (Map.Entry<String, Set<String>> entry : remove.entrySet()) {
+            String encoded = entry.getKey();
+            Set<String> paths = entry.getValue();
+            PropertyState property = index.getProperty(encoded);
+            if (property != null) {
+                List<CoreValue> values = Lists.newArrayList();
+                for (CoreValue value : property.getValues()) {
+                    if (!paths.contains(value.getString())) {
+                        values.add(value);
+                    }
+                }
+                if (values.isEmpty()) {
+                    index.removeProperty(encoded);
+                } else {
+                    index.setProperty(encoded, values);
+                }
+            }
+        }
+
+        for (Map.Entry<String, Set<String>> entry : insert.entrySet()) {
+            String encoded = entry.getKey();
+            Set<String> paths = entry.getValue();
+            List<CoreValue> values = Lists.newArrayList();
+            PropertyState property = index.getProperty(encoded);
+            if (property != null) {
+                for (CoreValue value : property.getValues()) {
+                    values.add(value);
+                    paths.remove(value.getString());
+                }
+            }
+            for (String path : paths) {
+                values.add(new StringValue(path));
+            }
+            if (values.isEmpty()) {
+                index.removeProperty(encoded);
+            } else if (unique && values.size() > 1) {
+                throw new CommitFailedException(
+                        "Uniqueness constraint violated");
+            } else {
+                index.setProperty(encoded, values);
+            }
+        }
+    }
+
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/InitialContent.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/InitialContent.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/InitialContent.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/type/InitialContent.java Thu Oct  4 09:04:28 2012
@@ -46,14 +46,16 @@ public class InitialContent extends Defa
             mk.commit("/", "^\"jcr:primaryType\":\"nam:rep:root\"" +
                     "+\"jcr:system\":{" +
                     "\"jcr:primaryType\"    :\"nam:rep:system\"," +
-                    // FIXME: user-mgt related unique properties (rep:authorizableId, rep:principalName) are implementation detail and not generic for repo
-                    // FIXME: rep:principalName only needs to be unique if defined with user/group nodes -> add defining nt-info to uniqueness constraint otherwise ac-editing will fail.
-                    "\":unique\"            :{\"jcr:uuid\":{},\"rep:authorizableId\":{},\"rep:principalName\":{}}," +
                     "\"jcr:versionStorage\" :{\"jcr:primaryType\":\"nam:rep:versionStorage\"}," +
                     "\"jcr:nodeTypes\"      :{\"jcr:primaryType\":\"nam:rep:nodeTypes\"}," +
                     "\"jcr:activities\"     :{\"jcr:primaryType\":\"nam:rep:Activities\"}," +
                     "\"rep:privileges\"     :{\"jcr:primaryType\":\"nam:rep:Privileges\"}}", null, null);
         }
+        if (!root.hasChildNode("oak:index")) {
+            // FIXME: user-mgt related unique properties (rep:authorizableId, rep:principalName) are implementation detail and not generic for repo
+            // FIXME: rep:principalName only needs to be unique if defined with user/group nodes -> add defining nt-info to uniqueness constraint otherwise ac-editing will fail.
+            mk.commit("/", "+\"oak:index\":{\"jcr:uuid\":{\"unique\":true},\"rep:authorizableId\":{\"unique\":true},\"rep:principalName\":{\"unique\":true}}", null, null);
+        }
 
         if (!root.hasChildNode("oak-index")) {
             mk.commit("/", "+\"oak-index\":{ \"indexes\": { \"type\": \"lucene\" }}", null, null);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java Thu Oct  4 09:04:28 2012
@@ -123,6 +123,12 @@ public interface NodeBuilder {
     @Nonnull
     NodeBuilder setProperty(String name, @Nonnull List<CoreValue> values);
 
+    @Nonnull
+    NodeBuilder set(String name, String value);
+
+    @Nonnull
+    NodeBuilder set(String name, String... values);
+
     /**
      * Remove the named property. This method has no effect if a
      * property of the given {@code name} does not exist.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java Thu Oct  4 09:04:28 2012
@@ -95,6 +95,16 @@ public class ReadOnlyBuilder implements 
     }
 
     @Override @Nonnull
+    public NodeBuilder set(String name, String value) {
+        throw unsupported();
+    }
+
+    @Override @Nonnull
+    public NodeBuilder set(String name, String... value) {
+        throw unsupported();
+    }
+
+    @Override @Nonnull
     public NodeBuilder removeProperty(String name) {
         throw unsupported();
     }

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexTest.java?rev=1393963&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/property/PropertyIndexTest.java Thu Oct  4 09:04:28 2012
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.property;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class PropertyIndexTest {
+
+    private static final int MANY = 100;
+
+    @Test
+    public void testPropertyLookup() throws Exception {
+        NodeState root = MemoryNodeState.EMPTY_NODE;
+
+        // Add index definition
+        NodeBuilder builder = root.getBuilder();
+        builder.getChildBuilder("oak:index").getChildBuilder("foo");
+        NodeState before = builder.getNodeState();
+
+        // Add some content and process it through the property index hook
+        builder = before.getBuilder();
+        builder.getChildBuilder("a").set("foo", "abc");
+        builder.getChildBuilder("b").set("foo", "abc", "def");
+        // plus lots of dummy content to highlight the benefit of indexing
+        for (int i = 0; i < MANY; i++) {
+            builder.getChildBuilder("n" + i).set("foo", "xyz");
+        }
+        NodeState after = builder.getNodeState();
+
+        // First check lookups without an index
+        PropertyIndexLookup lookup = new PropertyIndexLookup(after);
+        long withoutIndex = System.nanoTime();
+        assertEquals(ImmutableSet.of("a", "b"), lookup.find("foo", "abc"));
+        assertEquals(ImmutableSet.of("b"), lookup.find("foo", "def"));
+        assertEquals(ImmutableSet.of(), lookup.find("foo", "ghi"));
+        assertEquals(MANY, lookup.find("foo", "xyz").size());
+        withoutIndex = System.nanoTime() - withoutIndex;
+
+        // ... then see how adding an index affects the code
+        lookup = new PropertyIndexLookup(
+                new PropertyIndexHook().processCommit(before, after));
+        long withIndex = System.nanoTime();
+        assertEquals(ImmutableSet.of("a", "b"), lookup.find("foo", "abc"));
+        assertEquals(ImmutableSet.of("b"), lookup.find("foo", "def"));
+        assertEquals(ImmutableSet.of(), lookup.find("foo", "ghi"));
+        assertEquals(MANY, lookup.find("foo", "xyz").size());
+        withIndex = System.nanoTime() - withIndex;
+
+        // System.out.println("Index performance ratio: " + withoutIndex/withIndex);
+        // assertTrue(withoutIndex > withIndex);
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java Thu Oct  4 09:04:28 2012
@@ -31,7 +31,7 @@ import org.apache.jackrabbit.oak.api.Con
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.core.ContentRepositoryImpl;
-import org.apache.jackrabbit.oak.plugins.unique.UniqueIndexHook;
+import org.apache.jackrabbit.oak.plugins.property.PropertyIndexHook;
 import org.apache.jackrabbit.oak.spi.security.user.Type;
 import org.apache.jackrabbit.oak.spi.security.user.UserConfig;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
@@ -104,7 +104,7 @@ public class UserProviderImplTest extend
 
     @Override
     protected ContentRepository createRepository() {
-        return new ContentRepositoryImpl(new UniqueIndexHook());
+        return new ContentRepositoryImpl(new PropertyIndexHook());
     }
 
     private UserProvider createUserProvider() {

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt Thu Oct  4 09:04:28 2012
@@ -121,6 +121,10 @@ select * from [nt:base] as x where isdes
 /jcr:system
 /oak-index
 /oak-index/indexes
+/oak:index
+/oak:index/jcr:uuid
+/oak:index/rep:authorizableId
+/oak:index/rep:principalName
 /test
 /test/jcr:resource
 /test/resource
@@ -145,6 +149,7 @@ select * from [nt:base] as p inner join 
 /, /children
 /, /jcr:system
 /, /oak-index
+/, /oak:index
 /, /parents
 
 select * from [nt:base] as p inner join [nt:base] as p2 on isdescendantnode(p2, p) where p.[jcr:path] = '/parents'
@@ -201,6 +206,10 @@ select * from [nt:base] where not isdesc
 /jcr:system
 /oak-index
 /oak-index/indexes
+/oak:index
+/oak:index/jcr:uuid
+/oak:index/rep:authorizableId
+/oak:index/rep:principalName
 /test
 /test/hello
 /test/world
@@ -221,6 +230,10 @@ select * from [nt:base] where not (id = 
 /jcr:system
 /oak-index
 /oak-index/indexes
+/oak:index
+/oak:index/jcr:uuid
+/oak:index/rep:authorizableId
+/oak:index/rep:principalName
 /test
 /test/hello
 
@@ -229,6 +242,10 @@ select * from [nt:base] where x is null 
 /jcr:system
 /oak-index
 /oak-index/indexes
+/oak:index
+/oak:index/jcr:uuid
+/oak:index/rep:authorizableId
+/oak:index/rep:principalName
 /test
 
 commit / - "test"

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt Thu Oct  4 09:04:28 2012
@@ -27,52 +27,52 @@ commit / + "parents": { "p0": {"id": "0"
 commit / + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}}
 
 measure select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and not isdescendantnode(p, '/jcr:system')
-c, 627
-p, 209
+c, 639
+p, 213
 query, 4
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 4
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 1
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 3
 
 measure select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p
-c, 627
-p, 209
+c, 639
+p, 213
 query, 3
 
 measure select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and not isdescendantnode(p, '/jcr:system')
-c, 627
-p, 209
+c, 639
+p, 213
 query, 4
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 4
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 1
 
 measure select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null
-c, 627
-p, 209
+c, 639
+p, 213
 query, 3
 
 measure select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p
-c, 627
-p, 209
+c, 639
+p, 213
 query, 3
 

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java Thu Oct  4 09:04:28 2012
@@ -34,9 +34,9 @@ import org.apache.jackrabbit.oak.api.Con
 import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.property.PropertyIndexHook;
 import org.apache.jackrabbit.oak.plugins.type.InitialContent;
 import org.apache.jackrabbit.oak.plugins.type.TypeValidatorProvider;
-import org.apache.jackrabbit.oak.plugins.unique.UniqueIndexHook;
 import org.apache.jackrabbit.oak.security.SecurityProviderImpl;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeValidatorProvider;
 import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
@@ -68,7 +68,7 @@ public class RepositoryImpl implements R
     private static final CompositeHook DEFAULT_COMMIT_HOOK =
             new CompositeHook(
                     new ValidatingHook(DEFAULT_VALIDATOR),
-                    new UniqueIndexHook());
+                    new PropertyIndexHook());
 
     private final Descriptors descriptors = new Descriptors(new SimpleValueFactory());
     private final ContentRepository contentRepository;

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java Thu Oct  4 09:04:28 2012
@@ -229,12 +229,17 @@ public class RepositoryTest extends Abst
         root.getNode("bar").remove();  // transiently removed and...
         root.addNode("bar");           // ... added again
         NodeIterator nodes = root.getNodes();
-        // TODO: use a test subtree to avoid excluding default content
-        int expected = 3 + (root.hasNode("jcr:system") ? 1 : 0)  + (root.hasNode("oak-index") ? 1 : 0);
+        // FIXME: use a test subtree to avoid excluding default content
+        int expected = 3
+                + (root.hasNode("jcr:system") ? 1 : 0)
+                + (root.hasNode("oak-index") ? 1 : 0)
+                + (root.hasNode("oak:index") ? 1 : 0);
         assertEquals(expected, nodes.getSize());
         while (nodes.hasNext()) {
             String name = nodes.nextNode().getName();
-            if (!name.equals("jcr:system") && !name.equals("oak-index")) {
+            if (!name.equals("jcr:system")
+                    && !name.equals("oak-index")
+                    && !name.equals("oak:index")) {
                 assertTrue(nodeNames.remove(name));
             }
         }

Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java?rev=1393963&r1=1393962&r2=1393963&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java Thu Oct  4 09:04:28 2012
@@ -32,9 +32,9 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.lucene.LuceneReindexHook;
 import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.property.PropertyIndexHook;
 import org.apache.jackrabbit.oak.plugins.type.DefaultTypeEditor;
 import org.apache.jackrabbit.oak.plugins.type.TypeValidatorProvider;
-import org.apache.jackrabbit.oak.plugins.unique.UniqueIndexHook;
 import org.apache.jackrabbit.oak.security.privilege.PrivilegeValidatorProvider;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
@@ -200,7 +200,7 @@ public class Main {
             return new CompositeHook(
                     new DefaultTypeEditor(),
                     new ValidatingHook(createDefaultValidatorProvider()),
-                    new UniqueIndexHook(),
+                    new PropertyIndexHook(),
                     new LuceneReindexHook(DEFAULT_INDEX_HOME),
                     new LuceneHook(DEFAULT_INDEX_HOME));
         }