Author: mkataria
Date: Mon Feb 3 11:55:04 2020
New Revision: 1873532
URL: http://svn.apache.org/viewvc?rev=1873532&view=rev
Log:
OAK-8788: Add index creation and index completion time to indexes
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java
(with props)
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java
(with props)
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java
(with props)
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java
(with props)
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ReindexOperations.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java?rev=1873532&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java
Mon Feb 3 11:55:04 2020
@@ -0,0 +1,189 @@
+/*
+ * 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.indexversion;
+
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.query.IndexName;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/*
+ Main operation of this class is to mark IndexName's with operations
+ */
+public class IndexVersionOperation {
+ private static final Logger LOG =
LoggerFactory.getLogger(IndexVersionOperation.class);
+
+ private IndexName indexName;
+ private Operation operation;
+
+ public IndexVersionOperation(IndexName indexName) {
+ this.indexName = indexName;
+ this.operation = Operation.NOOP;
+ }
+
+ public void setOperation(Operation operation) {
+ this.operation = operation;
+ }
+
+ public Operation getOperation() {
+ return this.operation;
+ }
+
+ public IndexName getIndexName() {
+ return this.indexName;
+ }
+
+ @Override
+ public String toString() {
+ return this.getIndexName() + " operation:" + this.getOperation();
+ }
+
+ /**
+ * @param indexDefParentNode NodeState of parent of baseIndex
+ * @param indexNameObjectList This is a list of IndexName Objects with
same baseIndexName on which operations will be applied.
+ * @param purgeThresholdMillis after which a fully functional index is
eligible for purge operations
+ * @return This method returns an IndexVersionOperation list i.e
indexNameObjectList marked with operations
+ */
+ public static List<IndexVersionOperation>
generateIndexVersionOperationList(NodeState indexDefParentNode,
+
List<IndexName> indexNameObjectList, long purgeThresholdMillis) {
+ int activeProductVersion = -1;
+ List<IndexName> reverseSortedIndexNameList =
getReverseSortedIndexNameList(indexNameObjectList);
+ removeDisabledCustomIndexesFromList(indexDefParentNode,
reverseSortedIndexNameList);
+ List<IndexVersionOperation> indexVersionOperationList = new
LinkedList<>();
+ for (IndexName indexNameObject : reverseSortedIndexNameList) {
+ NodeState indexNode = indexDefParentNode
+
.getChildNode(PathUtils.getName(indexNameObject.getNodeName()));
+ /*
+ All Indexes are by default NOOP until we get index which is active
for more than threshold limit
+ */
+ if (activeProductVersion == -1) {
+ indexVersionOperationList.add(new
IndexVersionOperation(indexNameObject));
+ if (indexNode.hasChildNode(IndexDefinition.STATUS_NODE)) {
+ if (indexNode.getChildNode(IndexDefinition.STATUS_NODE)
+
.getProperty(IndexDefinition.REINDEX_COMPLETION_TIMESTAMP) != null) {
+ String reindexCompletionTime = indexDefParentNode
+
.getChildNode(PathUtils.getName(indexNameObject.getNodeName()))
+ .getChildNode(IndexDefinition.STATUS_NODE)
+
.getProperty(IndexDefinition.REINDEX_COMPLETION_TIMESTAMP).getValue(Type.DATE);
+ long reindexCompletionTimeInMillis =
PurgeOldVersionUtils.getMillisFromString(reindexCompletionTime);
+ long currentTimeInMillis = System.currentTimeMillis();
+ if (currentTimeInMillis -
reindexCompletionTimeInMillis > purgeThresholdMillis) {
+ activeProductVersion =
indexNameObject.getProductVersion();
+ }
+ } else {
+ LOG.warn(IndexDefinition.REINDEX_COMPLETION_TIMESTAMP
+ + " property is not set for index " +
indexNameObject.getNodeName());
+ }
+ }
+ } else {
+ /*
+ Once we found active index, we mark all its custom version with
DELETE
+ and OOTB same product version index with DELETE_HIDDEN_AND_DISABLE
+ */
+ if (indexNameObject.getProductVersion() == activeProductVersion
+ && indexNameObject.getCustomerVersion() == 0) {
+ IndexVersionOperation indexVersionOperation = new
IndexVersionOperation(indexNameObject);
+
indexVersionOperation.setOperation(Operation.DELETE_HIDDEN_AND_DISABLE);
+ indexVersionOperationList.add(indexVersionOperation);
+ } else {
+ IndexVersionOperation indexVersionOperation = new
IndexVersionOperation(indexNameObject);
+ indexVersionOperation.setOperation(Operation.DELETE);
+ indexVersionOperationList.add(indexVersionOperation);
+ }
+ }
+ }
+ if (!isValidIndexVersionOperationList(indexVersionOperationList)) {
+ indexVersionOperationList = Collections.emptyList();
+ }
+ return indexVersionOperationList;
+ }
+
+ /*
+ returns IndexNameObjects in descending order of version i.e from
newest version to oldest
+ */
+ private static List<IndexName>
getReverseSortedIndexNameList(List<IndexName> indexNameObjectList) {
+ List<IndexName> reverseSortedIndexNameObjectList = new
ArrayList<>(indexNameObjectList);
+ Collections.sort(reverseSortedIndexNameObjectList,
Collections.reverseOrder());
+ return reverseSortedIndexNameObjectList;
+ }
+
+ /**
+ * @param indexVersionOperations
+ * @return true if the IndexVersionOperation list passes following
criteria.
+ * For merging indexes we need baseIndex and latest custom index.
+ * So we first validate that if there are custom indexes than OOTB index
with same product must be marked with DELETE_HIDDEN_AND_DISABLE
+ */
+ private static boolean
isValidIndexVersionOperationList(List<IndexVersionOperation>
indexVersionOperations) {
+ boolean isValid = false;
+ IndexVersionOperation lastNoopOperationIndexVersion = null;
+ IndexVersionOperation indexWithDeleteHiddenOp = null;
+ for (IndexVersionOperation indexVersionOperation :
indexVersionOperations) {
+ if (indexVersionOperation.getOperation() == Operation.NOOP) {
+ lastNoopOperationIndexVersion = indexVersionOperation;
+ }
+ if (indexVersionOperation.getOperation() ==
Operation.DELETE_HIDDEN_AND_DISABLE) {
+ indexWithDeleteHiddenOp = indexVersionOperation;
+ }
+ }
+ if (lastNoopOperationIndexVersion.getIndexName().getCustomerVersion()
== 0) {
+ isValid = true;
+ } else if
(lastNoopOperationIndexVersion.getIndexName().getCustomerVersion() != 0) {
+ if (indexWithDeleteHiddenOp != null
+ &&
lastNoopOperationIndexVersion.getIndexName().getProductVersion() ==
indexWithDeleteHiddenOp.getIndexName().getProductVersion()) {
+ isValid = true;
+ }
+ }
+ if (!isValid) {
+ LOG.info("IndexVersionOperation List is not valid for index {}",
lastNoopOperationIndexVersion.getIndexName().getNodeName());
+ }
+ return isValid;
+ }
+
+ private static void removeDisabledCustomIndexesFromList(NodeState
indexDefParentNode,
+ List<IndexName>
indexNameObjectList) {
+ for (int i = 0; i < indexNameObjectList.size(); i++) {
+ NodeState indexNode = indexDefParentNode
+
.getChildNode(PathUtils.getName(indexNameObjectList.get(i).getNodeName()));
+ if (indexNode.getProperty("type") != null &&
"disabled".equals(indexNode.getProperty("type").getValue(Type.STRING))) {
+ indexNameObjectList.remove(i);
+ }
+ }
+ }
+
+ /*
+ NOOP means : No operation to be performed index Node
+ DELETE_HIDDEN_AND_DISABLE: This operation means that we should disable
this indexNode and delete all hidden nodes under it
+ DELETE: Delete this index altogether
+ */
+ enum Operation {
+ NOOP,
+ DELETE_HIDDEN_AND_DISABLE,
+ DELETE
+ }
+}
+
+
Propchange:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/IndexVersionOperation.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java?rev=1873532&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java
Mon Feb 3 11:55:04 2020
@@ -0,0 +1,170 @@
+/*
+ * 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.indexversion;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
+import org.apache.jackrabbit.oak.plugins.index.IndexPathServiceImpl;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.query.IndexName;
+import org.apache.jackrabbit.oak.run.cli.NodeStoreFixture;
+import org.apache.jackrabbit.oak.run.cli.NodeStoreFixtureProvider;
+import org.apache.jackrabbit.oak.run.cli.Options;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+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.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class PurgeOldIndexVersion {
+ private static final Logger LOG =
LoggerFactory.getLogger(PurgeOldIndexVersion.class);
+
+ public void execute(Options opts, long purgeThresholdMillis, List<String>
indexPaths) throws Exception {
+ boolean isReadWriteRepository = opts.getCommonOpts().isReadWrite();
+ if (!isReadWriteRepository) {
+ LOG.info("Repository connected in read-only mode. Use
'--read-write' for write operations");
+ }
+ try (NodeStoreFixture fixture = NodeStoreFixtureProvider.create(opts))
{
+ NodeStore nodeStore = fixture.getStore();
+ List<String> sanitisedIndexPaths =
sanitiseUserIndexPaths(indexPaths);
+ Set<String> indexPathSet =
filterIndexPaths(getRepositoryIndexPaths(nodeStore), sanitisedIndexPaths);
+ Map<String, Set<String>> segregateIndexes =
segregateIndexes(indexPathSet);
+ for (Map.Entry<String, Set<String>> entry :
segregateIndexes.entrySet()) {
+ String baseIndexPath = entry.getKey();
+ String parentPath = PathUtils.getParentPath(entry.getKey());
+ List<IndexName> indexNameObjectList =
getIndexNameObjectList(entry.getValue());
+ NodeState indexDefParentNode =
NodeStateUtils.getNode(nodeStore.getRoot(),
+ parentPath);
+ List<IndexVersionOperation> toDeleteIndexNameObjectList =
+
IndexVersionOperation.generateIndexVersionOperationList(indexDefParentNode,
indexNameObjectList, purgeThresholdMillis);
+ if (isReadWriteRepository &&
!toDeleteIndexNameObjectList.isEmpty()) {
+ purgeOldIndexVersion(nodeStore,
toDeleteIndexNameObjectList);
+ } else {
+ LOG.info("Repository is opened in read-only mode:
IndexOperations" +
+ " for index at path {} are : {}", baseIndexPath,
toDeleteIndexNameObjectList);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param userIndexPaths indexpaths provided by user
+ * @return a list of Indexpaths having baseIndexpaths or path till
oak:index
+ * @throws IllegalArgumentException if the paths provided are not till
oak:index or till index
+ */
+ private List<String> sanitiseUserIndexPaths(List<String> userIndexPaths) {
+ List<String> sanitisedUserIndexPaths = new ArrayList<>();
+ for (String userIndexPath : userIndexPaths) {
+ if
(PathUtils.getName(userIndexPath).equals(PurgeOldVersionUtils.OAK_INDEX)) {
+ sanitisedUserIndexPaths.add(userIndexPath);
+ } else if
(PathUtils.getName(PathUtils.getParentPath(userIndexPath)).equals(PurgeOldVersionUtils.OAK_INDEX))
{
+
sanitisedUserIndexPaths.add(IndexName.parse(userIndexPath).getBaseName());
+ } else {
+ throw new IllegalArgumentException(userIndexPath + " indexpath
is not valid");
+ }
+ }
+ return sanitisedUserIndexPaths;
+ }
+
+ /**
+ * @param indexPathSet
+ * @return a map with baseIndexName as key and a set of indexpaths having
same baseIndexName
+ */
+ private Map<String, Set<String>> segregateIndexes(Set<String>
indexPathSet) {
+ Map<String, Set<String>> segregatedIndexes = new HashMap<>();
+ for (String path : indexPathSet) {
+ String baseIndexPath = IndexName.parse(path).getBaseName();
+ Set<String> indexPaths = segregatedIndexes.get(baseIndexPath);
+ if (indexPaths == null) {
+ indexPaths = new HashSet<>();
+ }
+ indexPaths.add(path);
+ segregatedIndexes.put(baseIndexPath, indexPaths);
+ }
+ return segregatedIndexes;
+ }
+
+ private Iterable<String> getRepositoryIndexPaths(NodeStore store) throws
CommitFailedException, IOException {
+ IndexPathService indexPathService = new IndexPathServiceImpl(store);
+ return indexPathService.getIndexPaths();
+ }
+
+
+ /**
+ * @param repositoryIndexPaths: list of indexpaths retrieved from index
service
+ * @param commandlineIndexPaths indexpaths provided by user
+ * @return returns set of indexpaths which are to be considered for purging
+ */
+ private Set<String> filterIndexPaths(Iterable<String>
repositoryIndexPaths, List<String> commandlineIndexPaths) {
+ Set<String> filteredIndexPaths = new HashSet<>();
+ for (String commandlineIndexPath : commandlineIndexPaths) {
+ for (String repositoryIndexPath : repositoryIndexPaths) {
+ if
(PurgeOldVersionUtils.isIndexChildNode(commandlineIndexPath,
repositoryIndexPath)
+ ||
PurgeOldVersionUtils.isBaseIndexEqual(commandlineIndexPath,
repositoryIndexPath)) {
+ filteredIndexPaths.add(repositoryIndexPath);
+ }
+ }
+ }
+ return filteredIndexPaths;
+ }
+
+ private List<IndexName> getIndexNameObjectList(Set<String>
versionedIndexPaths) {
+ List<IndexName> indexNameObjectList = new ArrayList<>();
+ for (String indexNameString : versionedIndexPaths) {
+ indexNameObjectList.add(IndexName.parse(indexNameString));
+ }
+ return indexNameObjectList;
+ }
+
+ private void purgeOldIndexVersion(NodeStore store,
+ List<IndexVersionOperation>
toDeleteIndexNameObjectList) throws CommitFailedException {
+ for (IndexVersionOperation toDeleteIndexNameObject :
toDeleteIndexNameObjectList) {
+ NodeState root = store.getRoot();
+ NodeBuilder rootBuilder = root.builder();
+ NodeBuilder nodeBuilder =
PurgeOldVersionUtils.getNode(rootBuilder,
toDeleteIndexNameObject.getIndexName().getNodeName());
+ if (nodeBuilder.exists()) {
+ if (toDeleteIndexNameObject.getOperation() ==
IndexVersionOperation.Operation.DELETE_HIDDEN_AND_DISABLE) {
+ nodeBuilder.setProperty("type", "disabled", Type.STRING);
+
PurgeOldVersionUtils.recursiveDeleteHiddenChildNodes(store,
toDeleteIndexNameObject.getIndexName().getNodeName());
+ } else if (toDeleteIndexNameObject.getOperation() ==
IndexVersionOperation.Operation.DELETE) {
+ nodeBuilder.remove();
+ }
+ EditorHook hook = new EditorHook(
+ new IndexUpdateProvider(new
PropertyIndexEditorProvider()));
+ store.merge(rootBuilder, hook, CommitInfo.EMPTY);
+ } else {
+ LOG.error("nodebuilder null for path " +
toDeleteIndexNameObject.getIndexName().getNodeName());
+ }
+ }
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersion.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java?rev=1873532&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java
Mon Feb 3 11:55:04 2020
@@ -0,0 +1,102 @@
+/*
+ * 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.indexversion;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.property.RecursiveDelete;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.query.IndexName;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+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.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.util.ISO8601;
+import org.jetbrains.annotations.NotNull;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class PurgeOldVersionUtils {
+
+ public static final String OAK_INDEX = "oak:index";
+
+ public static long getMillisFromString(String strDate) {
+ return ISO8601.parse(strDate).getTimeInMillis();
+ }
+
+ /**
+ * @param nodeBuilder
+ * @param path Path of node whose nodeBuilder object should be
returned.
+ * @return nodeBuilder object of node at @param{path}
+ */
+ public static NodeBuilder getNode(@NotNull NodeBuilder nodeBuilder,
@NotNull String path) {
+ NodeBuilder resultNodeBuilder = nodeBuilder;
+ for (String name : PathUtils.elements(checkNotNull(path))) {
+ resultNodeBuilder =
resultNodeBuilder.getChildNode(checkNotNull(name));
+ }
+ return resultNodeBuilder;
+ }
+
+ /**
+ * @param store
+ * @param path
+ * @throws CommitFailedException recursively deletes child nodes under path
+ */
+ public static void recursiveDeleteHiddenChildNodes(NodeStore store, String
path) throws CommitFailedException {
+ NodeState nodeState = NodeStateUtils.getNode(store.getRoot(), path);
+ Iterable<String> childNodeNames = nodeState.getChildNodeNames();
+ for (String childNodeName : childNodeNames) {
+ if (NodeStateUtils.isHidden(childNodeName)) {
+ RecursiveDelete recursiveDelete = new RecursiveDelete(store,
EmptyHook.INSTANCE, () -> CommitInfo.EMPTY);
+ recursiveDelete.run(path + "/" + childNodeName);
+ }
+ }
+ }
+
+ /**
+ * @param commandlineIndexPath
+ * @param repositoryIndexPath
+ * @return true if baseIndexName at commandlineIndexPath and
repositoryIndexPath are equal
+ */
+ public static boolean isBaseIndexEqual(String commandlineIndexPath, String
repositoryIndexPath) {
+ if
(PathUtils.getName(PathUtils.getParentPath(commandlineIndexPath)).equals(OAK_INDEX))
{
+ String commandlineIndexBaseName =
IndexName.parse(commandlineIndexPath).getBaseName();
+ String repositoryIndexBaseName =
IndexName.parse(repositoryIndexPath).getBaseName();
+ if (commandlineIndexBaseName.equals(repositoryIndexBaseName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param commandlineIndexPath
+ * @param repositoryIndexPath
+ * @return true if repositoryIndexPath is child of commandlineIndexPath
+ */
+ public static boolean isIndexChildNode(String commandlineIndexPath, String
repositoryIndexPath) {
+ if (PathUtils.getName(commandlineIndexPath).equals(OAK_INDEX)) {
+ if (repositoryIndexPath.startsWith(commandlineIndexPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/indexversion/PurgeOldVersionUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java?rev=1873532&r1=1873531&r2=1873532&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
(original)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
Mon Feb 3 11:55:04 2020
@@ -64,5 +64,6 @@ public final class AvailableModes {
.put("search-nodes", new SearchNodesCommand())
.put("segment-copy", new SegmentCopyCommand())
.put("server", new ServerCommand())
+ .put("purge-index-versions", new PurgeOldIndexVersionCommand())
.build());
}
Added:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java?rev=1873532&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java
Mon Feb 3 11:55:04 2020
@@ -0,0 +1,55 @@
+/*
+ * 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.run;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import joptsimple.OptionSpec;
+import org.apache.jackrabbit.oak.indexversion.PurgeOldIndexVersion;
+import org.apache.jackrabbit.oak.run.cli.Options;
+import org.apache.jackrabbit.oak.run.commons.Command;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class PurgeOldIndexVersionCommand implements Command {
+ private long threshold;
+ private List<String> indexPaths;
+ private long DEFAULT_PURGE_THRESHOLD = TimeUnit.DAYS.toMillis(5); // 5
days in millis
+ private final static String DEFAULT_INDEX_PATH = "/oak:index";
+
+ @Override
+ public void execute(String... args) throws Exception {
+ Options opts = parseCommandLineParams(args);
+ new PurgeOldIndexVersion().execute(opts, threshold, indexPaths);
+ }
+
+ private Options parseCommandLineParams(String... args) throws Exception {
+ OptionParser parser = new OptionParser();
+ OptionSpec<Long> thresholdOption = parser.accepts("threshold")
+
.withOptionalArg().ofType(Long.class).defaultsTo(DEFAULT_PURGE_THRESHOLD);
+ OptionSpec<String> indexPathsOption = parser.accepts("index-paths",
"Comma separated list of index paths for which the " +
+ "selected operations need to be performed")
+
.withOptionalArg().ofType(String.class).withValuesSeparatedBy(",").defaultsTo(DEFAULT_INDEX_PATH);
+ Options opts = new Options();
+ OptionSet optionSet = opts.parseAndConfigure(parser, args);
+ this.threshold = optionSet.valueOf(thresholdOption);
+ this.indexPaths = optionSet.valuesOf(indexPathsOption);
+ return opts;
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/PurgeOldIndexVersionCommand.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java?rev=1873532&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java
(added)
+++
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java
Mon Feb 3 11:55:04 2020
@@ -0,0 +1,323 @@
+/*
+ * 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.indexversion;
+
+import ch.qos.logback.classic.Level;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.junit.LogCustomizer;
+import org.apache.jackrabbit.oak.index.AbstractIndexCommandTest;
+import org.apache.jackrabbit.oak.index.RepositoryFixture;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.run.PurgeOldIndexVersionCommand;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static org.apache.jackrabbit.commons.JcrUtils.getOrCreateByPath;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class PurgeOldIndexVersionTest extends AbstractIndexCommandTest {
+ private final static String FOO1_INDEX_PATH = "/oak:index/fooIndex1";
+
+ private void createCustomIndex(String path, int ootbVersion, int
customVersion, boolean asyncIndex) throws IOException, RepositoryException {
+ IndexDefinitionBuilder idxBuilder = new IndexDefinitionBuilder();
+ if (!asyncIndex) {
+ idxBuilder.noAsync();
+ }
+ idxBuilder.indexRule("nt:base").property("foo").propertyIndex();
+
+ Session session = fixture.getAdminSession();
+ String indexName = customVersion != 0
+ ? path + "-" + ootbVersion + "-custom-" + customVersion
+ : path + "-" + ootbVersion;
+ Node fooIndex = getOrCreateByPath(indexName,
+ "oak:QueryIndexDefinition", session);
+
+ idxBuilder.build(fooIndex);
+ session.save();
+ session.logout();
+ }
+
+ /*
+ All indexes have reindexCompletionTime present (Reindexing is done
after creating all indexes)
+ */
+ @Test
+ public void deleteOldIndexCompletely() throws Exception {
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ fixture.getAsyncIndexUpdate("async").run();
+ fixture.close();
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath(),
+ "--read-write",
+ "--threshold=1"
+ };
+
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+
+ Assert.assertFalse("Index:" + "fooIndex-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists());
+
Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING),
"disabled");
+
Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4")));
+ Assert.assertFalse("Index:" + "fooIndex-4-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists());
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists());
+ }
+
+ @Test
+ public void invalidIndexOperationVersion() throws Exception {
+
+ LogCustomizer custom = LogCustomizer
+ .forLogger(
+
"org.apache.jackrabbit.oak.indexversion.IndexVersionOperation")
+ .enable(Level.INFO).create();
+ try {
+ custom.starting();
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ fixture.getAsyncIndexUpdate("async").run();
+ fixture.close();
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+
+ // File outDir = temporaryFolder.newFolder();
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath(),
+ "--read-write",
+ "--threshold=1"
+ };
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+ List<String> logs = custom.getLogs();
+ assertTrue(logs.size() == 1);
+ assertThat("custom fooIndex don't have product version ",
logs.toString(),
+ containsString("IndexVersionOperation List is not valid
for index"));
+ } finally {
+ custom.finished();
+ }
+ }
+
+/*
+ Not all indexes have reIndexCompletionTime present (Reindexing is done
before creating all indexes)
+ We are deleting hidden nodes for indexes fooIndex-4-custom-2 and
fooIndex-3-custom-2
+ Now according to logic because fooIndex-4-custom-1 will have
reindexCompletionTimestamp all index
+ versions previous to this will get be marked for deletion or deleting
hidden node operation.
+ */
+
+ @Test
+ public void deleteOldIndexPartially() throws Exception {
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ fixture.getAsyncIndexUpdate("async").run();
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+
PurgeOldVersionUtils.recursiveDeleteHiddenChildNodes(fixture.getNodeStore(),
"/oak:index/fooIndex-4-custom-2");
+
PurgeOldVersionUtils.recursiveDeleteHiddenChildNodes(fixture.getNodeStore(),
"/oak:index/fooIndex-3-custom-2");
+ fixture.close();
+
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath(),
+ "--read-write",
+ "--threshold=1"
+ };
+
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+ Assert.assertFalse("Index:" + "fooIndex-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists());
+
Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING),
"disabled");
+
Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4")));
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists());
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists());
+ }
+
+ @Test
+ public void donotDeleteDisabledIndexes() throws Exception {
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ NodeStore store = fixture.getNodeStore();
+ NodeBuilder rootBuilder = store.getRoot().builder();
+ NodeBuilder nodeBuilder = rootBuilder.getChildNode("oak:index")
+ .getChildNode("fooIndex-4-custom-1").setProperty("type",
"disabled");
+ store.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ fixture.close();
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath(),
+ "--read-write",
+ "--threshold=1",
+ "--index-paths=/oak:index/fooIndex,/oak:index"
+ };
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+
+ Assert.assertFalse("Index:" + "fooIndex-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists());
+
Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING),
"disabled");
+
Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4")));
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists());
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists());
+ }
+
+ @Test
+ public void onlyDeleteVersionIndexesMentionedUnderIndexPaths() throws
Exception {
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ createCustomIndex(FOO1_INDEX_PATH, 2, 1, false);
+ createCustomIndex(FOO1_INDEX_PATH, 2, 2, false);
+ createCustomIndex(FOO1_INDEX_PATH, 3, 0, false);
+ createCustomIndex(FOO1_INDEX_PATH, 3, 1, false);
+ createCustomIndex(FOO1_INDEX_PATH, 3, 2, false);
+
+ fixture.getAsyncIndexUpdate("async").run();
+ fixture.close();
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath(),
+ "--read-write",
+ "--threshold=1",
+ "--index-paths=/oak:index/fooIndex"
+ };
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+
+ Assert.assertFalse("Index:" + "fooIndex-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists());
+ Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists());
+ Assert.assertFalse("Index:" + "fooIndex" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists());
+
Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING),
"disabled");
+
Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4")));
+ Assert.assertFalse("Index:" + "fooIndex-4-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists());
+ Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists());
+
+ Assert.assertTrue("Index:" + "fooIndex1-3-custom-1" + " deleted",
fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex1-3-custom-1").exists());
+ }
+
+ @Test
+ public void donotDeleteNonReadWriteMode() throws Exception {
+ LogCustomizer custom = LogCustomizer
+ .forLogger(
+
"org.apache.jackrabbit.oak.indexversion.PurgeOldIndexVersion")
+ .enable(Level.INFO).create();
+ try {
+ custom.starting();
+ createTestData(false);
+ createCustomIndex(TEST_INDEX_PATH, 2, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 3, 2, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 0, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 1, false);
+ createCustomIndex(TEST_INDEX_PATH, 4, 2, false);
+ fixture.getAsyncIndexUpdate("async").run();
+ fixture.close();
+ PurgeOldIndexVersionCommand command = new
PurgeOldIndexVersionCommand();
+
+ File storeDir = fixture.getDir();
+ String[] args = {
+ storeDir.getAbsolutePath()
+ };
+
+ command.execute(args);
+ fixture = new RepositoryFixture(storeDir);
+ fixture.close();
+ List<String> logs = custom.getLogs();
+ assertThat("repository is opened in read only mode ",
logs.toString(),
+ containsString("Repository is opened in read-only mode"));
+ } finally {
+ custom.finished();
+ }
+ }
+
+ private boolean isHiddenChildNodePresent(NodeState nodeState) {
+ boolean isHiddenChildNodePresent = false;
+ for (String childNodeName : nodeState.getChildNodeNames()) {
+ if (childNodeName.charAt(0) == ':') {
+ isHiddenChildNodePresent = true;
+ }
+ }
+ return isHiddenChildNodePresent;
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/indexversion/PurgeOldIndexVersionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java?rev=1873532&r1=1873531&r2=1873532&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
(original)
+++
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinition.java
Mon Feb 3 11:55:04 2020
@@ -143,6 +143,9 @@ public class IndexDefinition implements
*/
public static final String STATUS_LAST_UPDATED = "lastUpdated";
+ public static final String CREATION_TIMESTAMP = "creationTimestamp";
+ public static final String REINDEX_COMPLETION_TIMESTAMP =
"reindexCompletionTimestamp";
+
/**
* Meta property which provides the unique id
*/
Modified:
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ReindexOperations.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ReindexOperations.java?rev=1873532&r1=1873531&r2=1873532&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ReindexOperations.java
(original)
+++
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/ReindexOperations.java
Mon Feb 3 11:55:04 2020
@@ -22,14 +22,19 @@ package org.apache.jackrabbit.oak.plugin
import org.apache.jackrabbit.oak.plugins.index.search.util.NodeStateCloner;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.INDEX_DEFINITION_NODE;
+import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.REINDEX_COMPLETION_TIMESTAMP;
+import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.STATUS_NODE;
import static
org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexEditorContext.configureUniqueId;
/**
* Reindexing operations
*/
public class ReindexOperations {
+ private static final Logger LOG =
LoggerFactory.getLogger(ReindexOperations.class);
private final NodeState root;
private final NodeBuilder definitionBuilder;
private final String indexPath;
@@ -58,9 +63,12 @@ public class ReindexOperations {
NodeState defnState = useStateFromBuilder ?
definitionBuilder.getNodeState() : definitionBuilder.getBaseState();
if (!IndexDefinition.isDisableStoredIndexDefinition()) {
definitionBuilder.setChildNode(INDEX_DEFINITION_NODE,
NodeStateCloner.cloneVisibleState(defnState));
+ if (definitionBuilder.getChildNode(STATUS_NODE).exists()) {
+
definitionBuilder.getChildNode(STATUS_NODE).removeProperty(REINDEX_COMPLETION_TIMESTAMP);
+ LOG.info("{} property removed for index at {}",
REINDEX_COMPLETION_TIMESTAMP, this.indexPath);
+ }
}
String uid = configureUniqueId(definitionBuilder);
-
//Refresh the index definition based on update builder state
return indexDefBuilder
.root(root)
Modified:
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java?rev=1873532&r1=1873531&r2=1873532&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
(original)
+++
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
Mon Feb 3 11:55:04 2020
@@ -48,7 +48,10 @@ import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import static
org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PROP_RANDOM_SEED;
import static
org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PROP_REFRESH_DEFN;
+import static
org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.REGEX_ALL_PROPS;
import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.INDEX_DEFINITION_NODE;
+import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.REINDEX_COMPLETION_TIMESTAMP;
+import static
org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.STATUS_NODE;
/**
*
@@ -164,6 +167,11 @@ public abstract class FulltextIndexEdito
NodeBuilder status =
definitionBuilder.child(IndexDefinition.STATUS_NODE);
status.setProperty(IndexDefinition.STATUS_LAST_UPDATED,
getUpdatedTime(currentTime), Type.DATE);
status.setProperty("indexedNodes", indexedNodes);
+ if (!IndexDefinition.isDisableStoredIndexDefinition() && reindex) {
+ NodeBuilder indexDefinition = definitionBuilder.child(STATUS_NODE);
+
indexDefinition.setProperty(IndexDefinition.REINDEX_COMPLETION_TIMESTAMP,
ISO8601.format(currentTime), Type.DATE);
+ log.info(IndexDefinition.REINDEX_COMPLETION_TIMESTAMP + " set to
current time for index:" + definition.getIndexPath());
+ }
PERF_LOGGER.end(start, -1, "Overall Closed IndexWriter for directory
{}", definition);
@@ -267,14 +275,20 @@ public abstract class FulltextIndexEdito
definition.removeProperty(PROP_REFRESH_DEFN);
NodeState clonedState = NodeStateCloner.cloneVisibleState(defnState);
definition.setChildNode(INDEX_DEFINITION_NODE, clonedState);
+ definition.getChildNode(INDEX_DEFINITION_NODE)
+ .setProperty(IndexDefinition.CREATION_TIMESTAMP,
ISO8601.format(Calendar.getInstance()), Type.DATE);
log.info("Refreshed the index definition for [{}]",
indexingContext.getIndexPath());
+ log.info("IndexDefinition creation timestamp updated for [{}]",
indexingContext.getIndexPath());
if (log.isDebugEnabled()) {
log.debug("Updated index definition is {}",
NodeStateUtils.toString(clonedState));
}
} else if (!definition.hasChildNode(INDEX_DEFINITION_NODE)) {
definition.setChildNode(INDEX_DEFINITION_NODE,
NodeStateCloner.cloneVisibleState(defnState));
+ definition.getChildNode(INDEX_DEFINITION_NODE)
+ .setProperty(IndexDefinition.CREATION_TIMESTAMP,
ISO8601.format(Calendar.getInstance()), Type.DATE);
log.info("Stored the cloned index definition for [{}]. Changes in
index definition would now only be " +
"effective post reindexing", indexingContext.getIndexPath());
+ log.info("IndexDefinition creation timestamp added for [{}]",
indexingContext.getIndexPath());
} else {
// This is neither reindex nor refresh. So, let's update cloned def
with random seed
// if it doesn't match what's there in main definition
Modified:
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java?rev=1873532&r1=1873531&r2=1873532&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
(original)
+++
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
Mon Feb 3 11:55:04 2020
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
* If the node name doesn't contain version numbers / dashes, then version 0 is
* assumed (for both the product version number and customer version number).
*/
-class IndexName implements Comparable<IndexName> {
+public class IndexName implements Comparable<IndexName> {
private final static Logger LOG = LoggerFactory.getLogger(IndexName.class);
@@ -193,5 +193,29 @@ class IndexName implements Comparable<In
}
return false;
}
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public int getCustomerVersion() {
+ return customerVersion;
+ }
+
+ public int getProductVersion() {
+ return productVersion;
+ }
+
+ public String getBaseName() {
+ return baseName;
+ }
+
+ public boolean isVersioned() {
+ return isVersioned;
+ }
+
+ public boolean isLegal() {
+ return isLegal;
+ }
}
\ No newline at end of file