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