Author: chetanm
Date: Thu Oct 26 11:25:59 2017
New Revision: 1813386
URL: http://svn.apache.org/viewvc?rev=1813386&view=rev
Log:
OAK-6857 - Lucene unique index should check path validity for uniqueness
constraint
Check the path validity wrt current head state
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexUpdateCallback.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidator.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexLookupTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexStorageTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/SynchronousPropertyIndexTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidatorTest.java
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
Thu Oct 26 11:25:59 2017
@@ -183,7 +183,7 @@ public class LuceneIndexEditorProvider i
}
if (indexDefinition.hasSyncPropertyDefinitions()) {
- propertyUpdateCallback = new
PropertyIndexUpdateCallback(indexPath, definition);
+ propertyUpdateCallback = new
PropertyIndexUpdateCallback(indexPath, definition, root);
if (indexTracker != null) {
PropertyQuery query = new
LuceneIndexPropertyQuery(indexTracker, indexPath);
propertyUpdateCallback.getUniquenessConstraintValidator().setSecondStore(query);
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexUpdateCallback.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexUpdateCallback.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexUpdateCallback.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexUpdateCallback.java
Thu Oct 26 11:25:59 2017
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.oak.plugins
import
org.apache.jackrabbit.oak.plugins.index.property.strategy.UniqueEntryStoreStrategy;
import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.stats.Clock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,15 +62,15 @@ public class PropertyIndexUpdateCallback
private final UniquenessConstraintValidator uniquenessConstraintValidator;
private final long updateTime;
- public PropertyIndexUpdateCallback(String indexPath, NodeBuilder builder) {
- this(indexPath, builder, Clock.SIMPLE);
+ public PropertyIndexUpdateCallback(String indexPath, NodeBuilder builder,
NodeState rootState) {
+ this(indexPath, builder, rootState, Clock.SIMPLE);
}
- public PropertyIndexUpdateCallback(String indexPath, NodeBuilder builder,
Clock clock) {
+ public PropertyIndexUpdateCallback(String indexPath, NodeBuilder builder,
NodeState rootState, Clock clock) {
this.builder = builder;
this.indexPath = indexPath;
this.updateTime = clock.getTime();
- this.uniquenessConstraintValidator = new
UniquenessConstraintValidator(indexPath, builder);
+ this.uniquenessConstraintValidator = new
UniquenessConstraintValidator(indexPath, builder, rootState);
}
@Override
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidator.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidator.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidator.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidator.java
Thu Oct 26 11:25:59 2017
@@ -27,9 +27,15 @@ import com.google.common.collect.Immutab
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
/**
@@ -41,13 +47,15 @@ import static org.apache.jackrabbit.oak.
* - Lucene storage - Stores the long term index in lucene
*/
public class UniquenessConstraintValidator {
+ private final NodeState rootState;
private final String indexPath;
private final Multimap<String, String> uniqueKeys = HashMultimap.create();
private final PropertyQuery firstStore;
private PropertyQuery secondStore = PropertyQuery.DEFAULT;
- public UniquenessConstraintValidator(String indexPath, NodeBuilder
builder) {
+ public UniquenessConstraintValidator(String indexPath, NodeBuilder
builder, NodeState rootState) {
this.indexPath = indexPath;
+ this.rootState = rootState;
this.firstStore = new PropertyIndexQuery(builder);
}
@@ -75,7 +83,34 @@ public class UniquenessConstraintValidat
private Iterable<String> getIndexedPaths(String propertyRelativePath,
String value) {
return Iterables.concat(
firstStore.getIndexedPaths(propertyRelativePath, value),
- secondStore.getIndexedPaths(propertyRelativePath, value)
+ getValidPathsFromSecondStore(propertyRelativePath, value)
);
}
+
+ private Iterable<String> getValidPathsFromSecondStore(String
propertyRelativePath, String value) {
+ return filter(secondStore.getIndexedPaths(propertyRelativePath, value),
+ path -> {
+ NodeState node = NodeStateUtils.getNode(rootState, path);
+ if (!node.exists()) {
+ return false;
+ }
+ PropertyState uniqueProp = getValue(node,
propertyRelativePath);
+ if (uniqueProp == null) {
+ return false;
+ }
+ return uniqueProp.getValue(Type.STRING).equals(value);
+ });
+ }
+
+ private static PropertyState getValue(NodeState node, String
propertyRelativePath) {
+ int depth = PathUtils.getDepth(propertyRelativePath);
+ NodeState propNode = node;
+ String propName = propertyRelativePath;
+ if (depth > 1) {
+ propName = PathUtils.getName(propertyRelativePath);
+ String parentPath = PathUtils.getParentPath(propertyRelativePath);
+ propNode = NodeStateUtils.getNode(node, parentPath);
+ }
+ return propNode.getProperty(propName);
+ }
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexLookupTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexLookupTest.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexLookupTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexLookupTest.java
Thu Oct 26 11:25:59 2017
@@ -54,7 +54,7 @@ public class HybridPropertyIndexLookupTe
private NodeBuilder builder = EMPTY_NODE.builder();
private IndexDefinitionBuilder defnb = new IndexDefinitionBuilder();
private String indexPath = "/oak:index/foo";
- private PropertyIndexUpdateCallback callback = new
PropertyIndexUpdateCallback(indexPath, builder);
+ private PropertyIndexUpdateCallback callback = new
PropertyIndexUpdateCallback(indexPath, builder, root);
@Test
public void simplePropertyRestriction() throws Exception{
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexStorageTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexStorageTest.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexStorageTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/HybridPropertyIndexStorageTest.java
Thu Oct 26 11:25:59 2017
@@ -212,7 +212,7 @@ public class HybridPropertyIndexStorageT
}
private PropertyIndexUpdateCallback newCallback(){
- return new PropertyIndexUpdateCallback(indexPath, builder);
+ return new PropertyIndexUpdateCallback(indexPath, builder, root);
}
private PropertyDefinition pd(String propName){
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/PropertyIndexCleanerTest.java
Thu Oct 26 11:25:59 2017
@@ -312,7 +312,7 @@ public class PropertyIndexCleanerTest {
}
private PropertyIndexUpdateCallback newCallback(NodeBuilder builder,
String indexPath) {
- return new PropertyIndexUpdateCallback(indexPath, child(builder,
indexPath), clock);
+ return new PropertyIndexUpdateCallback(indexPath, child(builder,
indexPath), nodeStore.getRoot(), clock);
}
private PropertyDefinition pd(String indexPath, String propName){
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/SynchronousPropertyIndexTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/SynchronousPropertyIndexTest.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/SynchronousPropertyIndexTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/SynchronousPropertyIndexTest.java
Thu Oct 26 11:25:59 2017
@@ -217,6 +217,30 @@ public class SynchronousPropertyIndexTes
}
}
+ /**
+ * Test the scenario where a unique property is removed and then another
one
+ * with same value is added again
+ */
+ @Test
+ public void uniqueProperty_RemovedAndAsync() throws Exception{
+ defnb.async("async", "nrt");
+ defnb.indexRule("nt:base").property("foo").propertyIndex().unique();
+
+ addIndex(indexPath, defnb);
+ root.commit();
+
+ createPath("/a").setProperty("foo", "bar");
+ createPath("/a").setProperty("foo2", "bar2");
+ root.commit();
+ runAsyncIndex();
+
+ createPath("/a").removeProperty("foo");
+ root.commit();
+
+ createPath("/b").setProperty("foo", "bar");
+ root.commit();
+ }
+
@Test
public void nonUniqueIndex() throws Exception{
defnb.async("async", "nrt");
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidatorTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidatorTest.java?rev=1813386&r1=1813385&r2=1813386&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidatorTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/property/UniquenessConstraintValidatorTest.java
Thu Oct 26 11:25:59 2017
@@ -115,6 +115,23 @@ public class UniquenessConstraintValidat
public void secondStore_DiffPath() throws Exception{
defnb.indexRule("nt:base").property("foo").unique();
+ NodeBuilder rootBuilder = root.builder();
+ rootBuilder.child("b").setProperty("foo", "bar");
+ root = rootBuilder.getNodeState();
+
+ PropertyIndexUpdateCallback callback = newCallback();
+ propertyUpdated(callback, "/a", "foo", "bar");
+
+ callback.getUniquenessConstraintValidator()
+ .setSecondStore((propertyRelativePath, value) ->
singletonList("/b"));
+
+ callback.done();
+ }
+
+ @Test
+ public void secondStore_NodeNotExist() throws Exception{
+ defnb.indexRule("nt:base").property("foo").unique();
+
PropertyIndexUpdateCallback callback = newCallback();
propertyUpdated(callback, "/a", "foo", "bar");
@@ -124,13 +141,64 @@ public class UniquenessConstraintValidat
callback.done();
}
+ @Test
+ public void secondStore_NodeExist_PropertyNotExist() throws Exception{
+ defnb.indexRule("nt:base").property("foo").unique();
+
+ NodeBuilder rootBuilder = root.builder();
+ rootBuilder.child("b");
+ root = rootBuilder.getNodeState();
+
+ PropertyIndexUpdateCallback callback = newCallback();
+ propertyUpdated(callback, "/a", "foo", "bar");
+
+ callback.getUniquenessConstraintValidator()
+ .setSecondStore((propertyRelativePath, value) ->
singletonList("/b"));
+
+ callback.done();
+ }
+
+ @Test
+ public void secondStore_NodeExist_PropertyExist_DifferentValue() throws
Exception{
+ defnb.indexRule("nt:base").property("foo").unique();
+
+ NodeBuilder rootBuilder = root.builder();
+ rootBuilder.child("b").setProperty("foo", "bar2");
+ root = rootBuilder.getNodeState();
+
+ PropertyIndexUpdateCallback callback = newCallback();
+ propertyUpdated(callback, "/a", "foo", "bar");
+
+ callback.getUniquenessConstraintValidator()
+ .setSecondStore((propertyRelativePath, value) ->
singletonList("/b"));
+
+ callback.done();
+ }
+
+ @Test(expected = CommitFailedException.class)
+ public void secondStore_RelativeProperty() throws Exception{
+ defnb.indexRule("nt:base").property("jcr:content/foo").unique();
+
+ NodeBuilder rootBuilder = root.builder();
+ rootBuilder.child("b").child("jcr:content").setProperty("foo", "bar");
+ root = rootBuilder.getNodeState();
+
+ PropertyIndexUpdateCallback callback = newCallback();
+ propertyUpdated(callback, "/a", "jcr:content/foo", "bar");
+
+ callback.getUniquenessConstraintValidator()
+ .setSecondStore((propertyRelativePath, value) ->
singletonList("/b"));
+
+ callback.done();
+ }
+
private void propertyUpdated(PropertyUpdateCallback callback, String
nodePath, String propertyName, String value){
callback.propertyUpdated(nodePath, propertyName, pd(propertyName),
null, createProperty(propertyName, value));
}
private PropertyIndexUpdateCallback newCallback(){
- return new PropertyIndexUpdateCallback(indexPath, builder);
+ return new PropertyIndexUpdateCallback(indexPath, builder, root);
}
private PropertyDefinition pd(String propName){