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){


Reply via email to