Author: thomasm
Date: Tue Sep 1 08:58:03 2015
New Revision: 1700425
URL: http://svn.apache.org/r1700425
Log:
OAK-3263 Support including and excluding paths for PropertyIndex
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.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/PropertyIndexPlan.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/PathFilter.java
Tue Sep 1 08:58:03 2015
@@ -54,14 +54,17 @@ public class PathFilter {
public static final String PROP_EXCLUDED_PATHS = "excludedPaths";
public enum Result {
+
/**
* Include the path for processing
*/
INCLUDE,
+
/**
* Exclude the path and subtree for processing
*/
EXCLUDE,
+
/**
* Do not process the path but just perform traversal to
* child nodes. For IndexEditor it means that such nodes
@@ -72,7 +75,7 @@ public class PathFilter {
private static final PathFilter ALL = new PathFilter(INCLUDE_ROOT,
Collections.<String>emptyList()) {
@Override
- public Result doFiler(@Nonnull String path) {
+ public Result filter(@Nonnull String path) {
return Result.INCLUDE;
}
};
@@ -81,21 +84,23 @@ public class PathFilter {
private final String[] excludedPaths;
/**
- * Constructs the predicate based on given definition state. It looks
- * for multi value property with names {@link
PathFilter#PROP_INCLUDED_PATHS}
- * and {@link PathFilter#PROP_EXCLUDED_PATHS}. Both the properties
- * are optional.
- *
- * @param defn nodestate representing the configuration. Generally it
would be the nodestate
- * representing the index definition
+ * Constructs the predicate based on given definition state. It looks for
+ * multi value property with names {@link PathFilter#PROP_INCLUDED_PATHS}
+ * and {@link PathFilter#PROP_EXCLUDED_PATHS}. Both the properties are
+ * optional.
+ *
+ * @param defn nodestate representing the configuration. Generally it would
+ * be the nodestate representing the index definition
* @return predicate based on the passed definition state
*/
- public static PathFilter from(@Nonnull NodeBuilder defn){
- if (!defn.hasProperty(PROP_EXCLUDED_PATHS) &&
!defn.hasProperty(PROP_INCLUDED_PATHS)){
+ public static PathFilter from(@Nonnull NodeBuilder defn) {
+ if (!defn.hasProperty(PROP_EXCLUDED_PATHS) &&
+ !defn.hasProperty(PROP_INCLUDED_PATHS)) {
return ALL;
}
- return new PathFilter(getStrings(defn, PROP_INCLUDED_PATHS,
INCLUDE_ROOT),
- getStrings(defn, PROP_EXCLUDED_PATHS,
Collections.<String>emptyList()));
+ return new PathFilter(getStrings(defn, PROP_INCLUDED_PATHS,
+ INCLUDE_ROOT), getStrings(defn, PROP_EXCLUDED_PATHS,
+ Collections.<String> emptyList()));
}
/**
@@ -123,21 +128,21 @@ public class PathFilter {
* @param path path to check
* @return result indicating if the path needs to be included, excluded or
just traversed
*/
- public Result doFiler(@Nonnull String path) {
- for (String excludedPath : excludedPaths){
- if (excludedPath.equals(path) || isAncestor(excludedPath, path)){
+ public Result filter(@Nonnull String path) {
+ for (String excludedPath : excludedPaths) {
+ if (excludedPath.equals(path) || isAncestor(excludedPath, path)) {
return Result.EXCLUDE;
}
}
- for (String includedPath : includedPaths){
- if (includedPath.equals(path) || isAncestor(includedPath, path)){
+ for (String includedPath : includedPaths) {
+ if (includedPath.equals(path) || isAncestor(includedPath, path)) {
return Result.INCLUDE;
}
}
- for (String includedPath : includedPaths){
- if (includedPath.startsWith(path)){
+ for (String includedPath : includedPaths) {
+ if (isAncestor(path, includedPath)) {
return Result.TRAVERSE;
}
}
@@ -153,12 +158,35 @@ public class PathFilter {
'}';
}
- private static Iterable<String> getStrings(NodeBuilder builder, String
name, Collection<String> defaultVal) {
- PropertyState property = builder.getProperty(name);
+ private static Iterable<String> getStrings(NodeBuilder builder, String
propertyName,
+ Collection<String> defaultVal) {
+ PropertyState property = builder.getProperty(propertyName);
if (property != null && property.getType() == Type.STRINGS) {
return property.getValue(Type.STRINGS);
} else {
return defaultVal;
}
}
+
+ /**
+ * Check whether this node and all descendants are included in this filter.
+ *
+ * @param path the path
+ * @return true if this and all descendants of this path are included in
the filter
+ */
+ public boolean areAllDescendantsIncluded(String path) {
+ for (String excludedPath : excludedPaths) {
+ if (excludedPath.equals(path) || isAncestor(excludedPath, path) ||
+ isAncestor(path, excludedPath)) {
+ return false;
+ }
+ }
+ for (String includedPath : includedPaths) {
+ if (includedPath.equals(path) || isAncestor(includedPath, path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/OrderedPropertyIndexEditor.java
Tue Sep 1 08:58:03 2015
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.oak.api.Pro
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
import
org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy;
@@ -101,8 +102,8 @@ public class OrderedPropertyIndexEditor
swl = new StopwatchLogger(OrderedPropertyIndexEditor.class);
}
- OrderedPropertyIndexEditor(OrderedPropertyIndexEditor parent, String name)
{
- super(parent, name);
+ OrderedPropertyIndexEditor(OrderedPropertyIndexEditor parent, String name,
PathFilter.Result pathFilterResult) {
+ super(parent, name, pathFilterResult);
this.propertyNames = parent.getPropertyNames();
this.direction = parent.getDirection();
this.swl = parent.swl;
@@ -133,8 +134,8 @@ public class OrderedPropertyIndexEditor
@Override
PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor
parent,
- @Nonnull String name) {
- return new OrderedPropertyIndexEditor(this, name);
+ @Nonnull String name,
PathFilter.Result pathFilterResult) {
+ return new OrderedPropertyIndexEditor(this, name, pathFilterResult);
}
/**
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=1700425&r1=1700424&r2=1700425&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
Tue Sep 1 08:58:03 2015
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.oak.api.Pro
import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
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.plugins.index.property.strategy.UniqueEntryStoreStrategy;
@@ -110,6 +111,10 @@ class PropertyIndexEditor implements Ind
private final IndexUpdateCallback updateCallback;
+ private final PathFilter pathFilter;
+
+ private final PathFilter.Result pathFilterResult;
+
public PropertyIndexEditor(NodeBuilder definition, NodeState root,
IndexUpdateCallback updateCallback) {
this.parent = null;
@@ -117,6 +122,8 @@ class PropertyIndexEditor implements Ind
this.path = "/";
this.definition = definition;
this.root = root;
+ pathFilter = PathFilter.from(definition);
+ pathFilterResult = getPathFilterResult();
//initPropertyNames(definition);
@@ -147,7 +154,7 @@ class PropertyIndexEditor implements Ind
this.updateCallback = updateCallback;
}
- PropertyIndexEditor(PropertyIndexEditor parent, String name) {
+ PropertyIndexEditor(PropertyIndexEditor parent, String name,
PathFilter.Result pathFilterResult) {
this.parent = parent;
this.name = name;
this.path = null;
@@ -157,6 +164,8 @@ class PropertyIndexEditor implements Ind
this.typePredicate = parent.typePredicate;
this.keysToCheckForUniqueness = parent.keysToCheckForUniqueness;
this.updateCallback = parent.updateCallback;
+ this.pathFilter = parent.pathFilter;
+ this.pathFilterResult = pathFilterResult;
}
/**
@@ -228,6 +237,16 @@ class PropertyIndexEditor implements Ind
@Override
public void leave(NodeState before, NodeState after)
throws CommitFailedException {
+
+ if (pathFilterResult == PathFilter.Result.INCLUDE) {
+ applyTypeRestrictions(before, after);
+ updateIndex(before, after);
+ }
+ checkUniquenessConstraints();
+
+ }
+
+ private void applyTypeRestrictions(NodeState before, NodeState after) {
// apply the type restrictions
if (typePredicate != null) {
if (typeChanged) {
@@ -245,7 +264,9 @@ class PropertyIndexEditor implements Ind
afterKeys = null;
}
}
-
+ }
+
+ private void updateIndex(NodeState before, NodeState after) throws
CommitFailedException {
// if any changes were detected, update the index accordingly
if (beforeKeys != null || afterKeys != null) {
// first make sure that both the before and after sets are non-null
@@ -276,13 +297,17 @@ class PropertyIndexEditor implements Ind
}
}
+ checkUniquenessConstraints();
+ }
+
+ private void checkUniquenessConstraints() throws CommitFailedException {
if (parent == null) {
// make sure that the index node exist, even with no content
definition.child(INDEX_CONTENT_NODE_NAME);
boolean uniqueIndex = keysToCheckForUniqueness != null;
// check uniqueness constraints when leaving the root
- if (uniqueIndex &&
+ if (uniqueIndex &&
!keysToCheckForUniqueness.isEmpty()) {
NodeState indexMeta = definition.getNodeState();
String failed = getFirstDuplicate(
@@ -292,12 +317,12 @@ class PropertyIndexEditor implements Ind
"Uniqueness constraint violated at path [%s] for
one of the "
+ "property in %s having value %s",
getPath(), propertyNames, failed);
- throw new CommitFailedException(CONSTRAINT, 30, msg);
+ throw new CommitFailedException(CONSTRAINT, 30, msg);
}
}
}
}
-
+
/**
* From a set of keys, get those that already exist in the index.
*
@@ -378,24 +403,43 @@ class PropertyIndexEditor implements Ind
* @param name the name of the child node
* @return an instance of the PropertyIndexEditor
*/
- PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor
parent, @Nonnull String name) {
- return new PropertyIndexEditor(parent, name);
+ PropertyIndexEditor getChildIndexEditor(@Nonnull PropertyIndexEditor
parent, @Nonnull String name, PathFilter.Result filterResult) {
+ return new PropertyIndexEditor(parent, name, filterResult);
}
@Override
public Editor childNodeAdded(String name, NodeState after) {
- return getChildIndexEditor(this, name);
+ PathFilter.Result filterResult = getPathFilterResult(name);
+ if (filterResult == PathFilter.Result.EXCLUDE) {
+ return null;
+ }
+ return getChildIndexEditor(this, name, filterResult);
}
@Override
public Editor childNodeChanged(
String name, NodeState before, NodeState after) {
- return getChildIndexEditor(this, name);
+ PathFilter.Result filterResult = getPathFilterResult(name);
+ if (filterResult == PathFilter.Result.EXCLUDE) {
+ return null;
+ }
+ return getChildIndexEditor(this, name, filterResult);
}
@Override
public Editor childNodeDeleted(String name, NodeState before) {
- return getChildIndexEditor(this, name);
+ PathFilter.Result filterResult = getPathFilterResult(name);
+ if (filterResult == PathFilter.Result.EXCLUDE) {
+ return null;
+ }
+ return getChildIndexEditor(this, name, filterResult);
}
+ private PathFilter.Result getPathFilterResult() {
+ return pathFilter.filter(getPath());
+ }
+
+ private PathFilter.Result getPathFilterResult(String childNodeName) {
+ return pathFilter.filter(concat(getPath(), childNodeName));
+ }
}
\ No newline at end of file
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=1700425&r1=1700424&r2=1700425&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
Tue Sep 1 08:58:03 2015
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.Iterables.any;
-import static com.google.common.collect.Iterables.isEmpty;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static java.util.Collections.emptySet;
@@ -31,6 +30,8 @@ import java.util.Set;
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter.Result;
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.plugins.index.property.strategy.UniqueEntryStoreStrategy;
@@ -94,11 +95,14 @@ public class PropertyIndexPlan {
private final int depth;
+ private final PathFilter pathFilter;
+
PropertyIndexPlan(String name, NodeState root, NodeState definition,
Filter filter) {
this.name = name;
this.root = root;
this.definition = definition;
this.properties = newHashSet(definition.getNames(PROPERTY_NAMES));
+ pathFilter = PathFilter.from(definition.builder());
if (definition.getBoolean(UNIQUE_PROPERTY_NAME)) {
this.strategy = UNIQUE;
@@ -118,7 +122,8 @@ public class PropertyIndexPlan {
Set<String> bestValues = emptySet();
int bestDepth = 1;
- if (matchesNodeTypes) {
+ if (matchesNodeTypes &&
+ pathFilter.areAllDescendantsIncluded(filter.getPath())) {
for (String property : properties) {
PropertyRestriction restriction =
filter.getPropertyRestriction(property);
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/PathFilterTest.java
Tue Sep 1 08:58:03 2015
@@ -36,81 +36,84 @@ import static org.junit.Assert.fail;
public class PathFilterTest {
@Test
- public void exclude() throws Exception{
+ public void exclude() throws Exception {
PathFilter p = new PathFilter(of("/"), of("/etc"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/a"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/a"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
}
@Test
- public void include() throws Exception{
+ public void include() throws Exception {
PathFilter p = new PathFilter(of("/content", "/etc"),
of("/etc/workflow/instance"));
- assertEquals(PathFilter.Result.TRAVERSE, p.doFiler("/"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/var"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/content"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/content/example"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/workflow"));
- assertEquals(PathFilter.Result.EXCLUDE,
p.doFiler("/etc/workflow/instance"));
- assertEquals(PathFilter.Result.EXCLUDE,
p.doFiler("/etc/workflow/instance/1"));
+ assertEquals(PathFilter.Result.TRAVERSE, p.filter("/"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/var"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/content"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/content/example"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/workflow"));
+ assertEquals(PathFilter.Result.EXCLUDE,
p.filter("/etc/workflow/instance"));
+ assertEquals(PathFilter.Result.EXCLUDE,
p.filter("/etc/workflow/instance/1"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/x"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/e"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etcx"));
}
@Test
- public void emptyConfig() throws Exception{
+ public void emptyConfig() throws Exception {
NodeBuilder root = EMPTY_NODE.builder();
PathFilter p = PathFilter.from(root);
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/a"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/a"));
}
@Test
- public void config() throws Exception{
+ public void config() throws Exception {
NodeBuilder root = EMPTY_NODE.builder();
root.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/etc"),
Type.STRINGS));
root.setProperty(createProperty(PROP_EXCLUDED_PATHS,
of("/etc/workflow"), Type.STRINGS));
PathFilter p = PathFilter.from(root);
- assertEquals(PathFilter.Result.TRAVERSE, p.doFiler("/"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/a"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow/1"));
+ assertEquals(PathFilter.Result.TRAVERSE, p.filter("/"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/a"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow/1"));
}
@Test
- public void configOnlyExclude() throws Exception{
+ public void configOnlyExclude() throws Exception {
NodeBuilder root = EMPTY_NODE.builder();
root.setProperty(createProperty(PROP_EXCLUDED_PATHS,
of("/etc/workflow"), Type.STRINGS));
PathFilter p = PathFilter.from(root);
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc"));
- assertEquals(PathFilter.Result.INCLUDE, p.doFiler("/etc/a"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow"));
- assertEquals(PathFilter.Result.EXCLUDE, p.doFiler("/etc/workflow/1"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc"));
+ assertEquals(PathFilter.Result.INCLUDE, p.filter("/etc/a"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow"));
+ assertEquals(PathFilter.Result.EXCLUDE, p.filter("/etc/workflow/1"));
}
@Test
- public void invalid() throws Exception{
+ public void invalid() throws Exception {
try {
new PathFilter(Collections.<String>emptyList(), of("/etc"));
fail();
- } catch (IllegalStateException ignore){
-
+ } catch (IllegalStateException ignore) {
+ // expected
}
try {
new PathFilter(of("/etc/workflow"), of("/etc"));
fail();
- } catch (IllegalStateException ignore){
-
+ } catch (IllegalStateException ignore) {
+ // expected
}
try {
new PathFilter(Collections.<String>emptyList(),
Collections.<String>emptyList());
fail();
- } catch (IllegalStateException ignore){
-
+ } catch (IllegalStateException ignore) {
+ // expected
}
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/Oak2077QueriesTest.java
Tue Sep 1 08:58:03 2015
@@ -49,6 +49,7 @@ import org.apache.jackrabbit.oak.api.Res
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
+import org.apache.jackrabbit.oak.plugins.index.PathFilter;
import
org.apache.jackrabbit.oak.plugins.index.property.OrderedIndex.OrderDirection;
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.OrderedContentMirrorStoreStrategy;
@@ -169,8 +170,8 @@ public class Oak2077QueriesTest extends
this.rnd = rnd;
}
- public SeededPropertyIndexEditor(SeededPropertyIndexEditor parent,
String name) {
- super(parent, name);
+ public SeededPropertyIndexEditor(SeededPropertyIndexEditor parent,
String name, PathFilter.Result pathFilterResult) {
+ super(parent, name, pathFilterResult);
this.rnd = parent.rnd;
}
@@ -185,8 +186,8 @@ public class Oak2077QueriesTest extends
}
@Override
- PropertyIndexEditor getChildIndexEditor(PropertyIndexEditor parent,
String name) {
- return new SeededPropertyIndexEditor(this, name);
+ PropertyIndexEditor getChildIndexEditor(PropertyIndexEditor parent,
String name, PathFilter.Result pathFilterResult) {
+ return new SeededPropertyIndexEditor(this, name, pathFilterResult);
}
}
@@ -314,7 +315,7 @@ public class Oak2077QueriesTest extends
/**
* truncate the {@link AbstractQueryTest#TEST_INDEX_NAME} index at the 4th
element of the
* provided lane returning the previous value
- *
+ *
* @param lane the desired lane. Must be 0 <= {@code lane} < {@link
OrderedIndex#LANES}
* @param inexistent the derired value to be injected
* @return the value before the change
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java?rev=1700425&r1=1700424&r2=1700425&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
Tue Sep 1 08:58:03 2015
@@ -16,6 +16,8 @@
*/
package org.apache.jackrabbit.oak.plugins.index.property;
+import static com.google.common.collect.ImmutableSet.of;
+import static java.util.Arrays.asList;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
import static org.apache.jackrabbit.JcrConstants.NT_BASE;
@@ -23,14 +25,19 @@ import static org.apache.jackrabbit.JcrC
import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
import static
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+import static
org.apache.jackrabbit.oak.plugins.index.PathFilter.PROP_EXCLUDED_PATHS;
+import static
org.apache.jackrabbit.oak.plugins.index.PathFilter.PROP_INCLUDED_PATHS;
import static
org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditor.COUNT_PROPERTY_NAME;
import static
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
import static
org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
import java.util.Arrays;
import java.util.Set;
@@ -43,11 +50,13 @@ import ch.qos.logback.core.read.ListAppe
import ch.qos.logback.core.spi.FilterReply;
import com.google.common.collect.Iterables;
import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy;
import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.ast.Operator;
import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
import org.apache.jackrabbit.oak.query.index.TraversingIndex;
@@ -565,6 +574,165 @@ public class PropertyIndexTest {
deregisterAppender(appender);
}
+ @Test
+ public void testPathInclude() throws Exception {
+ NodeState root = INITIAL_CONTENT;
+
+ // Add index definition
+ NodeBuilder builder = root.builder();
+ NodeBuilder index =
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+ true, false, ImmutableSet.of("foo"), null);
+ index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"),
Type.STRINGS));
+ NodeState before = builder.getNodeState();
+
+ // Add some content and process it through the property index hook
+ builder.child("test").child("a").setProperty("foo", "abc");
+ builder.child("test").child("b").setProperty("foo", "abc");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after,
CommitInfo.EMPTY);
+
+ FilterImpl f = createFilter(indexed, NT_BASE);
+
+ // Query the index
+ PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+ assertEquals(ImmutableSet.of("test/a"), find(lookup, "foo", "abc", f));
+ }
+
+ @Test
+ public void testPathExclude() throws Exception {
+ NodeState root = INITIAL_CONTENT;
+
+ // Add index definition
+ NodeBuilder builder = root.builder();
+ NodeBuilder index =
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+ true, false, ImmutableSet.of("foo"), null);
+ index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"),
Type.STRINGS));
+ NodeState before = builder.getNodeState();
+
+ // Add some content and process it through the property index hook
+ builder.child("test").child("a").setProperty("foo", "abc");
+ builder.child("test").child("b").setProperty("foo", "abc");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after,
CommitInfo.EMPTY);
+
+ FilterImpl f = createFilter(indexed, NT_BASE);
+ f.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("abc"));
+
+ // Query the index
+ PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+ assertEquals(ImmutableSet.of("test/b"), find(lookup, "foo", "abc", f));
+
+ //no path restriction, opt out
+ PropertyIndexPlan plan = new PropertyIndexPlan("plan", root,
index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+ //path restriction is not an ancestor of excluded path, index may be
used
+ f.setPath("/test2");
+ plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY != plan.getCost());
+
+ //path restriction is an ancestor of excluded path, opt out
+ f.setPath("/test");
+ plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+ }
+
+ @Test
+ public void testPathIncludeExclude() throws Exception {
+ NodeState root = INITIAL_CONTENT;
+
+ // Add index definition
+ NodeBuilder builder = root.builder();
+ NodeBuilder index =
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+ true, false, ImmutableSet.of("foo"), null);
+ index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"),
Type.STRINGS));
+ index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a/b"),
Type.STRINGS));
+ NodeState before = builder.getNodeState();
+
+ // Add some content and process it through the property index hook
+ builder.child("test").child("a").setProperty("foo", "abc");
+ builder.child("test").child("a").child("b").setProperty("foo", "abc");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after,
CommitInfo.EMPTY);
+
+ FilterImpl f = createFilter(indexed, NT_BASE);
+ f.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("abc"));
+
+ // Query the index
+ PropertyIndexLookup lookup = new PropertyIndexLookup(indexed);
+ assertEquals(ImmutableSet.of("test/a"), find(lookup, "foo", "abc", f));
+
+ //no path restriction, opt out
+ PropertyIndexPlan plan = new PropertyIndexPlan("plan", root,
index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+ //path restriction is not an ancestor of excluded path, index may be
used
+ f.setPath("/test/a/x");
+ plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY != plan.getCost());
+
+ //path restriction is an ancestor of excluded path but no included
path, opt out
+ f.setPath("/test/a/b");
+ plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+
+ //path restriction is an ancestor of excluded path, opt out
+ f.setPath("/test/a");
+ plan = new PropertyIndexPlan("plan", root, index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+}
+
+ @Test
+ public void testPathExcludeInclude() throws Exception{
+ NodeState root = INITIAL_CONTENT;
+
+ // Add index definition
+ NodeBuilder builder = root.builder();
+ NodeBuilder index =
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+ true, false, ImmutableSet.of("foo"), null);
+ index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a/b"),
Type.STRINGS));
+ index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"),
Type.STRINGS));
+ NodeState before = builder.getNodeState();
+
+ // Add some content and process it through the property index hook
+ builder.child("test").child("a").setProperty("foo", "abc");
+ builder.child("test").child("a").child("b").setProperty("foo", "abc");
+ NodeState after = builder.getNodeState();
+
+ try {
+ HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ assertTrue(false);
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void testPathMismatch() throws Exception {
+ NodeState root = INITIAL_CONTENT;
+
+ // Add index definition
+ NodeBuilder builder = root.builder();
+ NodeBuilder index =
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME), "foo",
+ true, false, ImmutableSet.of("foo"), null);
+ index.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"),
Type.STRINGS));
+ index.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a/b"),
Type.STRINGS));
+ NodeState before = builder.getNodeState();
+
+ // Add some content and process it through the property index hook
+ builder.child("test").child("a").setProperty("foo", "abc");
+ builder.child("test").child("a").child("b").setProperty("foo", "abc");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after,
CommitInfo.EMPTY);
+
+ FilterImpl f = createFilter(indexed, NT_BASE);
+ f.restrictPath("/test2", Filter.PathRestriction.ALL_CHILDREN);
+ PropertyIndexPlan plan = new PropertyIndexPlan("plan", root,
index.getNodeState(), f);
+ assertTrue(Double.POSITIVE_INFINITY == plan.getCost());
+ }
+
private int getResultSize(NodeState indexed, String name, String value){
FilterImpl f = createFilter(indexed, NT_BASE);