Author: chetanm
Date: Mon Oct 16 04:17:07 2017
New Revision: 1812242

URL: http://svn.apache.org/viewvc?rev=1812242&view=rev
Log:
OAK-6820 - Implement support for disabling indexes which are replaced with 
newer index

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java
   (with props)
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdate.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporter.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdateTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporterTest.java
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexConstants.java
 Mon Oct 16 04:17:07 2017
@@ -125,4 +125,19 @@ public interface IndexConstants {
      */
     String REINDEX_RETAIN = "retainNodeInReindex";
 
+    /**
+     * Index type for disabled indexes
+     */
+    String TYPE_DISABLED = "disabled";
+
+    /**
+     * Multi value property referring to index paths which current index 
supersedes
+     */
+    String SUPERSEDED_INDEX_PATHS = "supersedes";
+
+    /**
+     * Boolean flag indicating that old indexes need to be disabled
+     */
+    String DISABLE_INDEXES_ON_NEXT_CYCLE = ":disableIndexesOnNextCycle";
+
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdate.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdate.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdate.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdate.java
 Mon Oct 16 04:17:07 2017
@@ -56,6 +56,7 @@ import org.apache.jackrabbit.oak.plugins
 import 
org.apache.jackrabbit.oak.plugins.index.progress.IndexingProgressReporter;
 import org.apache.jackrabbit.oak.plugins.index.progress.NodeCountEstimator;
 import org.apache.jackrabbit.oak.plugins.index.progress.TraversalRateEstimator;
+import org.apache.jackrabbit.oak.plugins.index.upgrade.IndexDisabler;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -143,7 +144,7 @@ public class IndexUpdate implements Edit
         this.parent = null;
         this.name = null;
         this.path = "/";
-        this.rootState = new IndexUpdateRootState(provider, async, root, 
updateCallback, traversalCallback, commitInfo, corruptIndexHandler);
+        this.rootState = new IndexUpdateRootState(provider, async, root, 
builder, updateCallback, traversalCallback, commitInfo, corruptIndexHandler);
         this.builder = checkNotNull(builder);
     }
 
@@ -281,7 +282,10 @@ public class IndexUpdate implements Edit
                         clearCorruptFlag(definition, indexPath);
                         reindex.put(concat(getPath(), INDEX_DEFINITIONS_NAME, 
name), editor);
                     }
+
+                    
rootState.indexDisabler.markDisableFlagIfRequired(indexPath, definition);
                 } else {
+                    rootState.indexDisabler.disableOldIndexes(indexPath, 
definition);
                     editors.add(editor);
                 }
             }
@@ -529,6 +533,7 @@ public class IndexUpdate implements Edit
         final String async;
         final NodeState root;
         final CommitInfo commitInfo;
+        final IndexDisabler indexDisabler;
         private boolean ignoreReindexFlags = IGNORE_REINDEX_FLAGS;
         final Set<IndexCommitCallback> indexCommitCallbacks = 
newIdentityHashSet();
         final CorruptIndexHandler corruptIndexHandler;
@@ -538,13 +543,15 @@ public class IndexUpdate implements Edit
         private MissingIndexProviderStrategy missingProvider = new 
MissingIndexProviderStrategy();
 
         private IndexUpdateRootState(IndexEditorProvider provider, String 
async, NodeState root,
-                                     IndexUpdateCallback updateCallback, 
NodeTraversalCallback traversalCallback,
+                                     NodeBuilder builder, IndexUpdateCallback 
updateCallback,
+                                     NodeTraversalCallback traversalCallback,
                                      CommitInfo commitInfo, 
CorruptIndexHandler corruptIndexHandler) {
             this.provider = checkNotNull(provider);
             this.async = async;
             this.root = checkNotNull(root);
             this.commitInfo = commitInfo;
             this.corruptIndexHandler = corruptIndexHandler;
+            this.indexDisabler = new IndexDisabler(builder);
             this.progressReporter = new 
IndexingProgressReporter(updateCallback, traversalCallback);
         }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporter.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporter.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporter.java
 Mon Oct 16 04:17:07 2017
@@ -36,6 +36,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
 import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
 import 
org.apache.jackrabbit.oak.plugins.index.importer.AsyncIndexerLock.LockToken;
+import org.apache.jackrabbit.oak.plugins.index.upgrade.IndexDisabler;
 import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
 import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -127,6 +128,7 @@ public class IndexImporter {
     void importIndexData() throws CommitFailedException, IOException {
         NodeState root = nodeStore.getRoot();
         NodeBuilder rootBuilder = root.builder();
+        IndexDisabler indexDisabler = new IndexDisabler(rootBuilder);
         for (IndexInfo indexInfo : asyncLaneToIndexMapping.values()) {
             log.info("Importing index data for {}", indexInfo.indexPath);
             NodeBuilder idxBuilder = indexDefinitionUpdater.apply(rootBuilder, 
indexInfo.indexPath);
@@ -141,6 +143,8 @@ public class IndexImporter {
             //TODO How to support CompositeNodeStore where some of the child 
nodes would be hidden
             incrementReIndexCount(idxBuilder);
             getImporter(indexInfo.type).importIndex(root, idxBuilder, 
indexInfo.indexDir);
+
+            indexDisabler.markDisableFlagIfRequired(indexInfo.indexPath, 
idxBuilder);
         }
         mergeWithConcurrentCheck(nodeStore, rootBuilder, indexEditorProvider);
     }

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java?rev=1812242&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java
 Mon Oct 16 04:17:07 2017
@@ -0,0 +1,159 @@
+/*
+ * 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.plugins.index.upgrade;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Collections.emptyList;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.SUPERSEDED_INDEX_PATHS;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_DISABLED;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+
+/**
+ * Checks and mark old indexes as disabled. It looks for 
IndexConstants#SUPERSEDED_INDEX_PATHS
+ * for the index paths which need to be marked as disabled. The index paths 
can refer to absolute
+ * index path or nodeTypes like /oak:index/nodetype/@foo where 'foo' is one of 
the nodetype indexed
+ * by /oak:index/nodetype
+ */
+public class IndexDisabler {
+    private static final Logger log = 
LoggerFactory.getLogger(IndexDisabler.class);
+    private final NodeBuilder rootBuilder;
+
+    public IndexDisabler(NodeBuilder rootBuilder) {
+        this.rootBuilder = rootBuilder;
+    }
+
+    public boolean markDisableFlagIfRequired(String currentIndexPath, 
NodeBuilder idxBuilder) {
+        boolean disableRequired = isAnyIndexToBeDisabled(currentIndexPath, 
idxBuilder);
+        if (disableRequired) {
+            idxBuilder.setProperty(DISABLE_INDEXES_ON_NEXT_CYCLE, true);
+        }
+        return disableRequired;
+    }
+
+    private boolean isAnyIndexToBeDisabled(String currentIndexPath, 
NodeBuilder idxBuilder) {
+        PropertyState indexPathsProp = 
idxBuilder.getProperty(SUPERSEDED_INDEX_PATHS);
+
+        if (indexPathsProp == null) {
+            return false;
+        }
+
+        Iterable<String> indexPaths = indexPathsProp.getValue(Type.STRINGS);
+        for (final String indexPath : indexPaths) {
+            if (isNodeTypePath(indexPath)) {
+                String nodeTypeName = 
PathUtils.getName(indexPath).substring(1);
+                String nodeTypeIndexPath = PathUtils.getParentPath(indexPath);
+
+                NodeState idxSate = 
NodeStateUtils.getNode(rootBuilder.getBaseState(), nodeTypeIndexPath);
+                PropertyState declaredNodeTypes = 
idxSate.getProperty(DECLARING_NODE_TYPES);
+                if (idxSate.exists() && declaredNodeTypes != null){
+                    if 
(Iterables.contains(declaredNodeTypes.getValue(Type.NAMES), nodeTypeName)) {
+                        return true;
+                    }
+                }
+            } else {
+                NodeState idxSate = 
NodeStateUtils.getNode(rootBuilder.getBaseState(), indexPath);
+                if (idxSate.exists() && 
!TYPE_DISABLED.equals(idxSate.getString(TYPE_PROPERTY_NAME))) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public List<String> disableOldIndexes(String currentIndexPath, NodeBuilder 
idxBuilder) {
+        PropertyState indexPathsProp = 
idxBuilder.getProperty(SUPERSEDED_INDEX_PATHS);
+
+        if (indexPathsProp == null) {
+            return emptyList();
+        }
+
+        if (!idxBuilder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE)) {
+            return emptyList();
+        }
+
+        //Skip disabling for the cycle where reindexing just got completed
+        if (idxBuilder.isReplaced(DISABLE_INDEXES_ON_NEXT_CYCLE)){
+            return emptyList();
+        }
+
+        Iterable<String> indexPaths = indexPathsProp.getValue(Type.STRINGS);
+        List<String> disabledIndexes = new ArrayList<>();
+        for (final String indexPath : indexPaths) {
+            if (isNodeTypePath(indexPath)) {
+                String nodeTypeName = 
PathUtils.getName(indexPath).substring(1);
+                String nodeTypeIndexPath = PathUtils.getParentPath(indexPath);
+
+                NodeBuilder nodeTypeIndexBuilder = child(rootBuilder, 
nodeTypeIndexPath);
+                PropertyState declaringNodeTypes = 
nodeTypeIndexBuilder.getProperty(DECLARING_NODE_TYPES);
+                if (nodeTypeIndexBuilder.exists() && declaringNodeTypes != 
null){
+                    Set<String> existingTypes = 
Sets.newHashSet(declaringNodeTypes.getValue(Type.NAMES));
+                    if (existingTypes.remove(nodeTypeName)) {
+                        disabledIndexes.add(indexPath);
+                        nodeTypeIndexBuilder.setProperty(DECLARING_NODE_TYPES, 
existingTypes, Type.NAMES);
+                    }
+                }
+            } else {
+                NodeBuilder disabledIndexBuilder = child(rootBuilder, 
indexPath);
+                if (disabledIndexBuilder.exists()) {
+                    disabledIndexBuilder.setProperty(TYPE_PROPERTY_NAME, 
TYPE_DISABLED);
+                    disabledIndexes.add(indexPath);
+                }
+            }
+        }
+
+        if (!disabledIndexes.isEmpty()) {
+            log.info("Index at [{}] supersedes indexes {}. Marking those as 
disabled",
+                    currentIndexPath, disabledIndexes);
+            idxBuilder.removeProperty(DISABLE_INDEXES_ON_NEXT_CYCLE);
+        }
+
+        return disabledIndexes;
+    }
+
+    private static boolean isNodeTypePath(String indexPath) {
+        String lastPathSegment = PathUtils.getName(indexPath);
+        return lastPathSegment.startsWith("@");
+    }
+
+    private static NodeBuilder child(NodeBuilder nb, String path) {
+        for (String name : PathUtils.elements(checkNotNull(path))) {
+            nb = nb.getChildNode(name);
+        }
+        return nb;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisabler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdateTest.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdateTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUpdateTest.java
 Mon Oct 16 04:17:07 2017
@@ -27,6 +27,7 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_ASYNC_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_COUNT;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
 import static org.apache.jackrabbit.oak.InitialContent.INITIAL_CONTENT;
 import static org.hamcrest.CoreMatchers.instanceOf;
@@ -875,6 +876,42 @@ public class IndexUpdateTest {
         }
     }
 
+    @Test
+    public void indexesDisabled() throws Exception{
+        NodeState before = builder.getNodeState();
+        createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), null);
+        createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+                "barIndex", true, false, ImmutableSet.of("bar"), null);
+        builder.child("testRoot").setProperty("foo", "abc");
+        NodeState after = builder.getNodeState();
+
+        NodeState indexed = HOOK.processCommit(before, after, 
CommitInfo.EMPTY);
+
+        before = indexed;
+        builder = indexed.builder();
+        NodeBuilder newIndex = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+                "newIndex", true, false, ImmutableSet.of("bar"), null);
+        newIndex.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS, 
asList("/oak:index/fooIndex"), Type.STRINGS);
+
+        after = builder.getNodeState();
+        indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+
+        //Post reindex also index should not be disabled
+        assertEquals("property", 
indexed.getChildNode("oak:index").getChildNode("fooIndex").getString(TYPE_PROPERTY_NAME));
+        
assertTrue(indexed.getChildNode("oak:index").getChildNode("newIndex").getBoolean(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE));
+
+        before = indexed;
+        builder = indexed.builder();
+        builder.child("testRoot2").setProperty("foo", "abc");
+        after = builder.getNodeState();
+        indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+
+        //Index only disabled after next cycle
+        assertEquals(IndexConstants.TYPE_DISABLED, 
indexed.getChildNode("oak:index").getChildNode("fooIndex").getString(TYPE_PROPERTY_NAME));
+        
assertFalse(indexed.getChildNode("oak:index").getChildNode("newIndex").getBoolean(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
     private static void markCorrupt(NodeBuilder builder, String indexName) {
         builder.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode(indexName)
                 .setProperty(IndexConstants.CORRUPT_PROPERTY_NAME, 
ISO8601.format(Calendar.getInstance()));

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporterTest.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporterTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/importer/IndexImporterTest.java
 Mon Oct 16 04:17:07 2017
@@ -72,6 +72,8 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_COUNT;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_DISABLED;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
 import static 
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
 import static 
org.apache.jackrabbit.oak.plugins.index.importer.AsyncIndexerLock.NOOP_LOCK;
 import static 
org.apache.jackrabbit.oak.plugins.index.importer.IndexDefinitionUpdater.INDEX_DEFINITIONS_JSON;
@@ -331,6 +333,53 @@ public class IndexImporterTest {
         assertEquals(2, idx.getLong("reindexCount"));
     }
 
+    @Test
+    public void importData_DisabledIndexes() throws Exception{
+        NodeBuilder builder = store.getRoot().builder();
+        NodeBuilder idxa = 
createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), null);
+        idxa.setProperty(ASYNC_PROPERTY_NAME, "async");
+        idxa.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS, 
asList("/oak:index/barIndex"), Type.STRINGS);
+
+        builder.child("a").setProperty("foo", "abc");
+        builder.child("b").setProperty("foo", "abc");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        new AsyncIndexUpdate("async", store, provider).run();
+
+        String checkpoint = createIndexDirs("/oak:index/fooIndex");
+
+        builder = store.getRoot().builder();
+
+        createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+                "barIndex", true, false, ImmutableSet.of("foo"), null);
+
+        builder.child("c").setProperty("foo", "abc");
+        builder.child("d").setProperty("foo", "abc");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        new AsyncIndexUpdate("async", store, provider).run();
+
+        IndexImporterProvider importerProvider = new IndexImporterProvider() {
+            @Override
+            public void importIndex(NodeState root, NodeBuilder defn, File 
indexDir) {
+            }
+
+            @Override
+            public String getType() {
+                return "property";
+            }
+        };
+
+        IndexImporter importer = new IndexImporter(store, 
temporaryFolder.getRoot(), provider, NOOP_LOCK);
+        importer.addImporterProvider(importerProvider);
+
+        importer.importIndex();
+
+        NodeState idx = 
store.getRoot().getChildNode("oak:index").getChildNode("barIndex");
+        assertEquals(TYPE_DISABLED, idx.getString(TYPE_PROPERTY_NAME));
+    }
+
     private NodeState getFooIndexNodeState() throws CommitFailedException {
         NodeState root = INITIAL_CONTENT;
         // Add index definition

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java?rev=1812242&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java
 Mon Oct 16 04:17:07 2017
@@ -0,0 +1,229 @@
+/*
+ * 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.plugins.index.upgrade;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_DISABLED;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.*;
+
+public class IndexDisablerTest {
+    private NodeBuilder builder = EMPTY_NODE.builder();
+    private NodeBuilder rootBuilder = EMPTY_NODE.builder();
+    private IndexDisabler disabler = new IndexDisabler(rootBuilder);
+
+    @Test
+    public void simpleIndex() throws Exception{
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes.isEmpty());
+    }
+
+    @Test
+    public void disableIndexes() throws Exception{
+        rootBuilder.child("oak:index").child("fooIndex");
+
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex", "/oak:index/barIndex"), 
Type.STRINGS);
+
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertThat(disabledIndexes, containsInAnyOrder("/oak:index/fooIndex"));
+        
assertFalse(builder.getBoolean(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE));
+        assertEquals(TYPE_DISABLED,
+                
rootBuilder.getChildNode("oak:index").getChildNode("fooIndex").getString(TYPE_PROPERTY_NAME));
+
+        //Check no node created for non existing node
+        
assertFalse(rootBuilder.getChildNode("oak:index").getChildNode("barIndex").exists());
+
+        builder = builder.getNodeState().builder();
+        List<String> disabledIndexes2 = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes2.isEmpty());
+    }
+
+    /**
+     * Test that indexes are not disabled in same cycle
+     * as when reindexing is done
+     */
+    @Test
+    public void reindexCase() throws Exception{
+        rootBuilder.child("oak:index").child("fooIndex");
+
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex", "/oak:index/barIndex"), 
Type.STRINGS);
+
+        builder = builder.getNodeState().builder();
+
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes.isEmpty());
+    }
+
+    @Test
+    public void nodeTypeIndexDisabling_noop() throws Exception{
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@bar"), Type.STRINGS);
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes.isEmpty());
+    }
+
+    @Test
+    public void nodeTypeIndexDisabling_noDeclaringTypes() throws Exception{
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        rootBuilder.child("oak:index").child("fooIndex");
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@bar"), Type.STRINGS);
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes.isEmpty());
+    }
+
+    @Test
+    public void nodeTypeIndexDisabling_typeNotExist() throws Exception{
+        createIndexDefinition(rootBuilder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), 
asList("oak:TestNode"));
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@oak:BarType"), Type.STRINGS);
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertTrue(disabledIndexes.isEmpty());
+    }
+
+    @Test
+    public void nodeTypeIndexDisabling_typeExist() throws Exception{
+        createIndexDefinition(rootBuilder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), 
asList("oak:TestNode", "oak:BarType"));
+
+        builder.setProperty(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE, 
true);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@oak:BarType"), Type.STRINGS);
+        List<String> disabledIndexes = 
disabler.disableOldIndexes("/oak:index/foo", builder);
+        assertThat(disabledIndexes, 
containsInAnyOrder("/oak:index/fooIndex/@oak:BarType"));
+        
assertFalse(builder.getBoolean(IndexConstants.DISABLE_INDEXES_ON_NEXT_CYCLE));
+
+
+        PropertyState declaringNodeType = 
rootBuilder.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("fooIndex").getProperty(DECLARING_NODE_TYPES);
+        assertEquals(Type.NAMES, declaringNodeType.getType());
+
+        Set<String> names = 
Sets.newHashSet(declaringNodeType.getValue(Type.NAMES));
+        assertThat(names, containsInAnyOrder("oak:TestNode"));
+    }
+
+    //~-------------------------------< anyIndexToBeDisabled >
+
+    @Test
+    public void indexToBeDisabled_Noop() throws Exception{
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void indexToBeDisabled_PathNotExists() throws Exception{
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void indexToBeDisabled_PathExistsButDisabled() throws Exception{
+        
rootBuilder.child("oak:index").child("fooIndex").setProperty(TYPE_PROPERTY_NAME,
 TYPE_DISABLED);
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void indexToBeDisabled_PathExists() throws Exception{
+        
rootBuilder.child("oak:index").child("fooIndex").setProperty(TYPE_PROPERTY_NAME,
 "property");
+        recreateDisabler();
+
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertTrue(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertTrue(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void nodeTypeIndexToBeDisabled_PathNotExists() throws Exception{
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@bar", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void nodeTypeIndexToBeDisabled_DeclaringTypeNotExists() throws 
Exception{
+        rootBuilder.child("oak:index").child("fooIndex");
+        recreateDisabler();
+
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@bar", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    @Test
+    public void nodeTypeIndexToBeDisabled_TypeNotExists() throws Exception{
+        createIndexDefinition(rootBuilder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), 
asList("oak:TestNode"));
+        recreateDisabler();
+
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@bar", "/oak:index/barIndex"), 
Type.STRINGS);
+        assertFalse(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertFalse(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+
+    @Test
+    public void nodeTypeIndexToBeDisabled_TypeExists() throws Exception{
+        createIndexDefinition(rootBuilder.child(INDEX_DEFINITIONS_NAME),
+                "fooIndex", true, false, ImmutableSet.of("foo"), 
asList("oak:TestNode"));
+        recreateDisabler();
+
+        builder.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS,
+                asList("/oak:index/fooIndex/@oak:TestNode", 
"/oak:index/barIndex"), Type.STRINGS);
+        assertTrue(disabler.markDisableFlagIfRequired("/oak:index/foo", 
builder));
+        assertTrue(builder.getBoolean(DISABLE_INDEXES_ON_NEXT_CYCLE));
+    }
+
+    private void recreateDisabler() {
+        disabler = new IndexDisabler(rootBuilder.getNodeState().builder());
+    }
+
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/upgrade/IndexDisablerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java
 Mon Oct 16 04:17:07 2017
@@ -100,6 +100,11 @@ public final class IndexDefinitionBuilde
         return this;
     }
 
+    public IndexDefinitionBuilder supersedes(String ... paths){
+        tree.setProperty(IndexConstants.SUPERSEDED_INDEX_PATHS, asList(paths), 
STRINGS);
+        return this;
+    }
+
     public IndexDefinitionBuilder codec(String codecName){
         tree.setProperty(LuceneIndexConstants.CODEC_NAME, 
checkNotNull(codecName));
         return this;

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java?rev=1812242&r1=1812241&r2=1812242&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java
 Mon Oct 16 04:17:07 2017
@@ -63,6 +63,7 @@ public class IndexDefinitionBuilderTest
     public void indexRule() throws Exception{
         builder.includedPaths("/a", "/b");
         builder.queryPaths("/c", "/d");
+        builder.supersedes("/e", "/f");
         builder.indexRule("nt:base")
                     .property("foo")
                         .ordered()
@@ -79,6 +80,7 @@ public class IndexDefinitionBuilderTest
         
assertTrue(state.getChildNode("indexRules").getChildNode("nt:base").exists());
         assertEquals(asList("/a", "/b"), 
state.getProperty(PathFilter.PROP_INCLUDED_PATHS).getValue(Type.STRINGS));
         assertEquals(asList("/c", "/d"), 
state.getProperty(IndexConstants.QUERY_PATHS).getValue(Type.STRINGS));
+        assertEquals(asList("/e", "/f"), 
state.getProperty(IndexConstants.SUPERSEDED_INDEX_PATHS).getValue(Type.STRINGS));
     }
 
     @Test


Reply via email to