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 2013/12/12 00:24:31 UTC
svn commit: r1550314 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins:
index/property/PropertyIndexEditor.java nodetype/TypePredicate.java
Author: jukka
Date: Wed Dec 11 23:24:31 2013
New Revision: 1550314
URL: http://svn.apache.org/r1550314
Log:
OAK-1273: Reduce overhead when handling many parallel property indices
Use lazy evaluation of node type restrictions in the property index
Modified:
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/nodetype/TypePredicate.java
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=1550314&r1=1550313&r2=1550314&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 Wed Dec 11 23:24:31 2013
@@ -18,6 +18,8 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Collections.singleton;
+import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
import static org.apache.jackrabbit.oak.api.Type.NAME;
import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -76,27 +78,26 @@ class PropertyIndexEditor implements Ind
private final Set<String> propertyNames;
+ /** Type predicate, or {@code null} if there are no type restrictions */
private final Predicate<NodeState> typePredicate;
- private final boolean unique;
-
+ /**
+ * Keys to check for uniqueness, or {@code null} for no uniqueness checks.
+ */
private final Set<String> keysToCheckForUniqueness;
/**
- * Flag to indicate whether individual property changes should
- * be tracked for this node.
+ * Flag to indicate whether the type of this node may have changed.
*/
- private boolean trackChanges;
+ private boolean typeChanged;
/**
- * Matching property value keys from the before state,
- * or {@code null} if this node is not indexed.
+ * Matching property value keys from the before state. Lazily initialized.
*/
private Set<String> beforeKeys;
/**
- * Matching property value keys from the after state,
- * or {@code null} if this node is not indexed.
+ * Matching property value keys from the after state. Lazily initialized.
*/
private Set<String> afterKeys;
@@ -120,15 +121,13 @@ class PropertyIndexEditor implements Ind
this.typePredicate = new TypePredicate(
root, definition.getNames(DECLARING_NODE_TYPES));
} else {
- this.typePredicate = NodeState.EXISTS;
+ this.typePredicate = null;
}
// keep track of modified keys for uniqueness checks
if (definition.getBoolean(IndexConstants.UNIQUE_PROPERTY_NAME)) {
- unique = true;
this.keysToCheckForUniqueness = newHashSet();
} else {
- unique = false;
this.keysToCheckForUniqueness = null;
}
}
@@ -140,7 +139,6 @@ class PropertyIndexEditor implements Ind
this.definition = parent.definition;
this.propertyNames = parent.propertyNames;
this.typePredicate = parent.typePredicate;
- this.unique = parent.unique;
this.keysToCheckForUniqueness = parent.keysToCheckForUniqueness;
}
@@ -154,42 +152,38 @@ class PropertyIndexEditor implements Ind
return path;
}
- private static void addValueKeys(Set<String> keys, PropertyState property) {
- if (property.getType().tag() != PropertyType.BINARY) {
+ /**
+ * Adds the encoded values of the given property to the given set.
+ * If the given set is uninitialized, i.e. {@code null}, then a new
+ * set is created for any values to be added. The set, possibly newly
+ * initialized, is returned.
+ *
+ * @param keys set of encoded values, or {@code null}
+ * @param property property whose values are to be added to the set
+ * @return set of encoded values, possibly initialized
+ */
+ private static Set<String> addValueKeys(
+ Set<String> keys, PropertyState property) {
+ if (property.getType().tag() != PropertyType.BINARY
+ && property.count() > 0) {
+ if (keys == null) {
+ keys = newHashSet();
+ }
keys.addAll(encode(PropertyValues.create(property)));
}
+ return keys;
}
- private static void addMatchingKeys(
- Set<String> keys, NodeState state, Iterable<String> propertyNames) {
+ private static Set<String> getMatchingKeys(
+ NodeState state, Iterable<String> propertyNames) {
+ Set<String> keys = null;
for (String propertyName : propertyNames) {
PropertyState property = state.getProperty(propertyName);
if (property != null) {
- addValueKeys(keys, property);
+ keys = addValueKeys(keys, property);
}
}
- }
-
- @Override
- public void enter(NodeState before, NodeState after)
- throws CommitFailedException {
- boolean beforeMatches = typePredicate.apply(before);
- boolean afterMatches = typePredicate.apply(after);
-
- if (beforeMatches || afterMatches) {
- beforeKeys = newHashSet();
- afterKeys = newHashSet();
- }
-
- if (beforeMatches && afterMatches) {
- trackChanges = true;
- } else if (beforeMatches) {
- // all matching values should be removed from the index
- addMatchingKeys(beforeKeys, before, propertyNames);
- } else if (afterMatches) {
- // all matching values should be added to the index
- addMatchingKeys(afterKeys, after, propertyNames);
- }
+ return keys;
}
private static IndexStoreStrategy getStrategy(boolean unique) {
@@ -197,20 +191,54 @@ class PropertyIndexEditor implements Ind
}
@Override
+ public void enter(NodeState before, NodeState after) {
+ typeChanged = (typePredicate == null); // disables property name checks
+ beforeKeys = null;
+ afterKeys = null;
+ }
+
+ @Override
public void leave(NodeState before, NodeState after)
throws CommitFailedException {
- if (beforeKeys != null) {
- Set<String> sharedKeys = newHashSet(beforeKeys);
- sharedKeys.retainAll(afterKeys);
+ // apply the type restrictions
+ if (typePredicate != null) {
+ if (typeChanged) {
+ // possible type change, so ignore diff results and
+ // just load all matching values from both states
+ beforeKeys = getMatchingKeys(before, propertyNames);
+ afterKeys = getMatchingKeys(after, propertyNames);
+ }
+ if (beforeKeys != null && !typePredicate.apply(before)) {
+ // the before state doesn't match the type, so clear its values
+ beforeKeys = null;
+ }
+ if (afterKeys != null && !typePredicate.apply(after)) {
+ // the after state doesn't match the type, so clear its values
+ afterKeys = null;
+ }
+ }
- beforeKeys.removeAll(sharedKeys);
- afterKeys.removeAll(sharedKeys);
+ // 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
+ if (beforeKeys == null
+ || (typePredicate != null && !typePredicate.apply(before))) {
+ beforeKeys = newHashSet();
+ } else if (afterKeys == null) {
+ afterKeys = newHashSet();
+ } else {
+ // both before and after matches found, remove duplicates
+ Set<String> sharedKeys = newHashSet(beforeKeys);
+ sharedKeys.retainAll(afterKeys);
+ beforeKeys.removeAll(sharedKeys);
+ afterKeys.removeAll(sharedKeys);
+ }
if (!beforeKeys.isEmpty() || !afterKeys.isEmpty()) {
NodeBuilder index = definition.child(INDEX_CONTENT_NODE_NAME);
-
- getStrategy(unique).update(index, getPath(), beforeKeys, afterKeys);
- if (unique) {
+ getStrategy(keysToCheckForUniqueness != null).update(
+ index, getPath(), beforeKeys, afterKeys);
+ if (keysToCheckForUniqueness != null) {
keysToCheckForUniqueness.addAll(afterKeys);
}
}
@@ -221,9 +249,10 @@ class PropertyIndexEditor implements Ind
definition.child(INDEX_CONTENT_NODE_NAME);
// check uniqueness constraints when leaving the root
- if (unique && !keysToCheckForUniqueness.isEmpty()) {
+ if (keysToCheckForUniqueness != null
+ && !keysToCheckForUniqueness.isEmpty()) {
NodeState indexMeta = definition.getNodeState();
- IndexStoreStrategy s = getStrategy(unique);
+ IndexStoreStrategy s = getStrategy(true);
for (String key : keysToCheckForUniqueness) {
if (s.count(indexMeta, singleton(key), 2) > 1) {
throw new CommitFailedException(
@@ -235,25 +264,35 @@ class PropertyIndexEditor implements Ind
}
}
+ private boolean isTypeProperty(String name) {
+ return JCR_PRIMARYTYPE.equals(name) || JCR_MIXINTYPES.equals(name);
+ }
+
@Override
public void propertyAdded(PropertyState after) {
- if (trackChanges && propertyNames.contains(after.getName())) {
- addValueKeys(afterKeys, after);
+ String name = after.getName();
+ typeChanged = typeChanged || isTypeProperty(name);
+ if (propertyNames.contains(name)) {
+ afterKeys = addValueKeys(afterKeys, after);
}
}
@Override
public void propertyChanged(PropertyState before, PropertyState after) {
- if (trackChanges && propertyNames.contains(after.getName())) {
- addValueKeys(beforeKeys, before);
- addValueKeys(afterKeys, after);
+ String name = after.getName();
+ typeChanged = typeChanged || isTypeProperty(name);
+ if (propertyNames.contains(name)) {
+ beforeKeys = addValueKeys(beforeKeys, before);
+ afterKeys = addValueKeys(afterKeys, after);
}
}
@Override
public void propertyDeleted(PropertyState before) {
- if (trackChanges && propertyNames.contains(before.getName())) {
- addValueKeys(beforeKeys, before);
+ String name = before.getName();
+ typeChanged = typeChanged || isTypeProperty(name);
+ if (propertyNames.contains(name)) {
+ beforeKeys = addValueKeys(beforeKeys, before);
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java?rev=1550314&r1=1550313&r2=1550314&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java Wed Dec 11 23:24:31 2013
@@ -21,7 +21,7 @@ import static com.google.common.base.Pre
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Sets.newHashSet;
-import static com.google.common.collect.Sets.union;
+import static java.util.Collections.singleton;
import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
@@ -37,6 +37,7 @@ import javax.annotation.Nonnull;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
/**
* Inheritance-aware node type predicate for {@link NodeState node states}.
@@ -45,9 +46,13 @@ import com.google.common.base.Predicate;
*/
public class TypePredicate implements Predicate<NodeState> {
- private final Set<String> primaryTypes = newHashSet();
+ private final NodeState root;
- private final Set<String> mixinTypes = newHashSet();
+ private final Iterable<String> names;
+
+ private Set<String> primaryTypes = null;
+
+ private Set<String> mixinTypes = null;
/**
* Creates a predicate for checking whether a node state is an instance of
@@ -58,10 +63,7 @@ public class TypePredicate implements Pr
* @param name Oak name of the node type to check for
*/
public TypePredicate(@Nonnull NodeState root, @Nonnull String name) {
- NodeState types = checkNotNull(root)
- .getChildNode(JCR_SYSTEM)
- .getChildNode(JCR_NODE_TYPES);
- addNodeType(types, checkNotNull(name));
+ this(root, singleton(name));
}
/**
@@ -74,12 +76,8 @@ public class TypePredicate implements Pr
*/
public TypePredicate(
@Nonnull NodeState root, @Nonnull Iterable<String> names) {
- NodeState types = checkNotNull(root)
- .getChildNode(JCR_SYSTEM)
- .getChildNode(JCR_NODE_TYPES);
- for (String name : checkNotNull(names)) {
- addNodeType(types, name);
- }
+ this.root = root;
+ this.names = names;
}
private void addNodeType(NodeState types, String name) {
@@ -101,6 +99,18 @@ public class TypePredicate implements Pr
@Override
public boolean apply(NodeState input) {
+ if (primaryTypes == null) {
+ // lazy initialization of the sets of matching type names
+ primaryTypes = newHashSet();
+ mixinTypes = newHashSet();
+ NodeState types = checkNotNull(root)
+ .getChildNode(JCR_SYSTEM)
+ .getChildNode(JCR_NODE_TYPES);
+ for (String name : checkNotNull(names)) {
+ addNodeType(types, name);
+ }
+ }
+
return primaryTypes.contains(input.getName(JCR_PRIMARYTYPE))
|| any(input.getNames(JCR_MIXINTYPES), in(mixinTypes));
}
@@ -109,7 +119,7 @@ public class TypePredicate implements Pr
@Override
public String toString() {
- return union(primaryTypes, mixinTypes).toString();
+ return Iterables.toString(names);
}
}