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 2016/10/07 12:34:52 UTC
svn commit: r1763756 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java
Author: thomasm
Date: Fri Oct 7 12:34:52 2016
New Revision: 1763756
URL: http://svn.apache.org/viewvc?rev=1763756&view=rev
Log:
OAK-4904 For unique indexes avoid consulting indexes other than property index
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java?rev=1763756&r1=1763755&r2=1763756&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java Fri Oct 7 12:34:52 2016
@@ -54,7 +54,7 @@ public class PropertyIndexPlan {
/**
* The cost overhead to use the index in number of read operations.
*/
- static final double COST_OVERHEAD = 2;
+ public static final double COST_OVERHEAD = 2;
/**
* The maximum cost when the index can be used.
@@ -83,6 +83,8 @@ public class PropertyIndexPlan {
private final PathFilter pathFilter;
+ private final boolean unique;
+
PropertyIndexPlan(String name, NodeState root, NodeState definition,
Filter filter){
this(name, root, definition, filter, Mounts.defaultMountInfoProvider());
@@ -91,6 +93,7 @@ public class PropertyIndexPlan {
PropertyIndexPlan(String name, NodeState root, NodeState definition,
Filter filter, MountInfoProvider mountInfoProvider) {
this.name = name;
+ this.unique = definition.getBoolean(IndexConstants.UNIQUE_PROPERTY_NAME);
this.definition = definition;
this.properties = newHashSet(definition.getNames(PROPERTY_NAMES));
pathFilter = PathFilter.from(definition.builder());
@@ -107,7 +110,7 @@ public class PropertyIndexPlan {
Set<String> bestValues = emptySet();
int bestDepth = 1;
- if (matchesNodeTypes &&
+ if (matchesNodeTypes &&
pathFilter.areAllDescendantsIncluded(filter.getPath())) {
for (String property : properties) {
PropertyRestriction restriction =
@@ -145,10 +148,20 @@ public class PropertyIndexPlan {
cost += strategy.count(filter, root, definition,
values, MAX_COST);
}
+ if (unique && cost <= 1) {
+ // for unique index, for the normal case
+ // (that is, for a regular lookup)
+ // no further reads are needed
+ cost = 0;
+ }
if (cost < bestCost) {
bestDepth = depth;
bestValues = values;
bestCost = cost;
+ if (bestCost == 0) {
+ // shortcut: not possible to top this
+ break;
+ }
}
}
}
@@ -207,8 +220,6 @@ public class PropertyIndexPlan {
Set<IndexStoreStrategy> getStrategies(NodeState definition,
MountInfoProvider mountInfoProvider) {
- boolean unique = definition
- .getBoolean(IndexConstants.UNIQUE_PROPERTY_NAME);
return Multiplexers.getStrategies(unique, mountInfoProvider,
definition, INDEX_CONTENT_NODE_NAME);
}
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java?rev=1763756&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/IndexSelectionTest.java Fri Oct 7 12:34:52 2016
@@ -0,0 +1,137 @@
+/*
+ * 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.query.index;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexPlan;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.spi.query.Cursor;
+import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class IndexSelectionTest extends AbstractQueryTest {
+ private TestIndexProvider testIndexProvider = new TestIndexProvider();
+ @Override
+ protected ContentRepository createRepository() {
+ return new Oak()
+ .with(new OpenSecurityProvider())
+ .with(new InitialContent())
+ .with(new PropertyIndexEditorProvider())
+ .with(new PropertyIndexProvider())
+ .with(testIndexProvider)
+ .createContentRepository();
+ }
+
+ @Test
+ public void uuidIndexQuery() throws Exception{
+ NodeUtil node = new NodeUtil(root.getTree("/"));
+ String uuid = UUID.randomUUID().toString();
+ node.setString(JcrConstants.JCR_UUID, uuid);
+ root.commit();
+
+ assertQuery("SELECT * FROM [nt:base] WHERE [jcr:uuid] = '"+uuid+"' ",
+ ImmutableList.of("/"));
+ assertEquals("Test index plan should not be invoked",
+ 0, testIndexProvider.index.invocationCount);
+ }
+
+ @Test
+ public void uuidIndexNotNullQuery() throws Exception{
+ NodeUtil node = new NodeUtil(root.getTree("/"));
+ String uuid = UUID.randomUUID().toString();
+ node.setString(JcrConstants.JCR_UUID, uuid);
+ root.commit();
+
+ assertQuery("SELECT * FROM [nt:base] WHERE [jcr:uuid] is not null",
+ ImmutableList.of("/"));
+ assertEquals("Test index plan should be invoked",
+ 1, testIndexProvider.index.invocationCount);
+ }
+
+ @Test
+ public void uuidIndexInListQuery() throws Exception{
+ NodeUtil node = new NodeUtil(root.getTree("/"));
+ String uuid = UUID.randomUUID().toString();
+ String uuid2 = UUID.randomUUID().toString();
+ node.setString(JcrConstants.JCR_UUID, uuid);
+ root.commit();
+
+ assertQuery("SELECT * FROM [nt:base] WHERE [jcr:uuid] in('" + uuid + "', '" + uuid2 + "')",
+ ImmutableList.of("/"));
+ assertEquals("Test index plan should be invoked",
+ 1, testIndexProvider.index.invocationCount);
+ }
+
+ private static class TestIndexProvider implements QueryIndexProvider {
+ TestIndex index = new TestIndex();
+ @Nonnull
+ @Override
+ public List<? extends QueryIndex> getQueryIndexes(NodeState nodeState) {
+ return ImmutableList.<QueryIndex>of(index);
+ }
+ }
+
+ private static class TestIndex implements QueryIndex {
+ int invocationCount = 0;
+ @Override
+ public double getMinimumCost() {
+ return PropertyIndexPlan.COST_OVERHEAD + 0.1;
+ }
+
+ @Override
+ public double getCost(Filter filter, NodeState rootState) {
+ invocationCount++;
+ return Double.POSITIVE_INFINITY;
+ }
+
+ @Override
+ public Cursor query(Filter filter, NodeState rootState) {
+ return null;
+ }
+
+ @Override
+ public String getPlan(Filter filter, NodeState rootState) {
+ return null;
+ }
+
+ @Override
+ public String getIndexName() {
+ return "test-index";
+ }
+ }
+}
\ No newline at end of file