You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2019/10/31 07:34:34 UTC
svn commit: r1869202 - in /jackrabbit/oak/trunk:
oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/
oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/
oak-lucene/src/test/java/org/apache/jackrabbit/oak...
Author: thomasm
Date: Thu Oct 31 07:34:34 2019
New Revision: 1869202
URL: http://svn.apache.org/viewvc?rev=1869202&view=rev
Log:
OAK-8721 Automatically pick the latest active index version
Added:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/Persistence.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReaderFactory.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/LuceneIndexReaderFactory.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java Thu Oct 31 07:34:34 2019
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
import org.apache.jackrabbit.oak.spi.commit.SubtreeEditor;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
import org.apache.jackrabbit.oak.spi.mount.Mounts;
import org.apache.jackrabbit.oak.spi.state.EqualsDiff;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -97,6 +98,10 @@ public class IndexTracker {
this.readerFactory = readerFactory;
this.nrtFactory = nrtFactory;
}
+
+ public MountInfoProvider getMountInfoProvider() {
+ return readerFactory.getMountInfoProvider();
+ }
public synchronized void close() {
Map<String, LuceneIndexNodeManager> indices = this.indices;
@@ -304,4 +309,5 @@ public class IndexTracker {
private static boolean isIndexDefinitionChanged(NodeState before, NodeState after) {
return !EqualsDiff.equals(before.getChildNode(INDEX_DEFINITION_NODE), after.getChildNode(INDEX_DEFINITION_NODE));
}
+
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java Thu Oct 31 07:34:34 2019
@@ -720,6 +720,11 @@ public class LucenePropertyIndex extends
protected String getType() {
return TYPE_LUCENE;
}
+
+ @Override
+ protected boolean filterReplacedIndexes() {
+ return tracker.getMountInfoProvider().hasNonDefaultMounts();
+ }
@Override
protected SizeEstimator getSizeEstimator(IndexPlan plan) {
@@ -1715,4 +1720,5 @@ public class LucenePropertyIndex extends
static abstract class LuceneResultRowIterator extends AbstractIterator<FulltextResultRow> implements IteratorRewoundStateProvider {
}
+
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReaderFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReaderFactory.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReaderFactory.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReaderFactory.java Thu Oct 31 07:34:34 2019
@@ -126,4 +126,9 @@ public class DefaultIndexReaderFactory i
}
return null;
}
+
+ @Override
+ public MountInfoProvider getMountInfoProvider() {
+ return mountInfoProvider;
+ }
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/LuceneIndexReaderFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/LuceneIndexReaderFactory.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/LuceneIndexReaderFactory.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/LuceneIndexReaderFactory.java Thu Oct 31 07:34:34 2019
@@ -23,9 +23,13 @@ import java.io.IOException;
import java.util.List;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
import org.apache.jackrabbit.oak.spi.state.NodeState;
public interface LuceneIndexReaderFactory {
List<LuceneIndexReader> createReaders(LuceneIndexDefinition definition, NodeState definitionState, String indexPath) throws IOException;
+
+ MountInfoProvider getMountInfoProvider();
+
}
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java?rev=1869202&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java Thu Oct 31 07:34:34 2019
@@ -0,0 +1,129 @@
+/*
+ * 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.composite.blueGreen;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Tests customized indexes.
+ */
+public class CustomizedIndexTest {
+
+ private final Persistence.Config config = new Persistence.Config();
+
+ @Rule
+ public TemporaryFolder tempDir = new TemporaryFolder(new File("target"));
+
+ private File globalDir;
+ private File libs1Dir;
+ private File libs2Dir;
+ private File datastoreDir;
+ private File indexDir;
+
+ @Test
+ public void test() throws Exception {
+ createFolders();
+ config.blobStore = Persistence.getFileBlobStore(datastoreDir);
+ config.indexDir = indexDir;
+ initLibs1();
+ initGlobal();
+ compositeLibs1();
+ initLibs2();
+ compositeLibs2();
+ }
+
+ private void initLibs1() throws Exception {
+ Persistence p = Persistence.open(libs1Dir, config);
+ p.session.getRootNode().addNode("libs").addNode("test").setProperty("foo", "a");
+ p.session.save();
+ IndexUtils.createIndex(p, "test-1", "foo", 10);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo]",
+ "test-1",
+ "[/libs/test]");
+ p.close();
+ }
+
+ private void initGlobal() throws Exception {
+ Persistence p = Persistence.open(globalDir, config);
+ p.session.getRootNode().addNode("content").addNode("test").setProperty("foo", "a");
+ p.session.save();
+ p.close();
+ }
+
+ private void compositeLibs1() throws Exception {
+ Persistence p = Persistence.openComposite(globalDir, libs1Dir, config);
+ IndexUtils.checkLibsIsReadOnly(p);
+ IndexUtils.createIndex(p, "test-1", "foo", 10);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-1",
+ "[/content/test, /libs/test]");
+ p.close();
+ }
+
+ private void compositeLibs2() throws Exception {
+ Persistence p = Persistence.openComposite(globalDir, libs2Dir, config);
+ IndexUtils.checkLibsIsReadOnly(p);
+ IndexUtils.createIndex(p, "test-2", "foo", 20);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-2",
+ "[/content/test, /libs/test2]");
+ p.close();
+ // the new index must not be used in the old version (wiht libs1)
+ p = Persistence.openComposite(globalDir, libs1Dir, config);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-1",
+ "[/content/test, /libs/test]");
+ p.close();
+ }
+
+ private void initLibs2() throws Exception {
+ Persistence p = Persistence.open(libs2Dir, config);
+ p.session.getRootNode().addNode("libs").addNode("test2").setProperty("foo", "a");
+ p.session.save();
+ IndexUtils.createIndex(p, "test-1", "foo", 10);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo]",
+ "test-1",
+ "[/libs/test2]");
+ IndexUtils.createIndex(p, "test-2", "foo", 20);
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo]",
+ "test-2",
+ "[/libs/test2]");
+ p.close();
+ }
+
+ private void createFolders() throws IOException {
+ globalDir = tempDir.newFolder("global");
+ libs1Dir = tempDir.newFolder("libs1");
+ libs2Dir = tempDir.newFolder("libs2");
+ datastoreDir = tempDir.newFolder("datastore");
+ indexDir = tempDir.newFolder("index");
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java?rev=1869202&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java Thu Oct 31 07:34:34 2019
@@ -0,0 +1,148 @@
+/*
+ * 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.composite.blueGreen;
+
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexFormatVersion;
+import org.junit.Assert;
+
+/**
+ * Utilities for indexing and query tests.
+ */
+public class IndexUtils {
+
+ /**
+ * Create an index and wait until it is ready.
+ *
+ * @param p the persistence
+ * @param indexName the name of the index
+ * @param propertyName the property to index (on nt:base)
+ * @param cost the cost per execution (high means the index isn't used if possible)
+ */
+ public static void createIndex(Persistence p, String indexName, String propertyName, double cost) throws RepositoryException {
+ Node indexDef = p.session.getRootNode().getNode("oak:index");
+ Node index = indexDef.addNode(indexName, INDEX_DEFINITIONS_NODE_TYPE);
+ index.setProperty(TYPE_PROPERTY_NAME, LuceneIndexConstants.TYPE_LUCENE);
+ index.setProperty(IndexConstants.REINDEX_PROPERTY_NAME, true);
+ index.setProperty(FulltextIndexConstants.COMPAT_MODE, IndexFormatVersion.V2.getVersion());
+ index.setProperty(IndexConstants.ASYNC_PROPERTY_NAME,
+ new String[] { "async", "nrt" });
+ index.setProperty(FulltextIndexConstants.COST_PER_EXECUTION, cost);
+ // index.setProperty("excludedPaths", "/jcr:system");
+ Node indexRules = index.addNode(FulltextIndexConstants.INDEX_RULES);
+ Node ntBase = indexRules.addNode("nt:base");
+ Node props = ntBase.addNode(FulltextIndexConstants.PROP_NODE);
+ Node foo = props.addNode(propertyName);
+ foo.setProperty(FulltextIndexConstants.PROP_NAME, propertyName);
+ foo.setProperty(FulltextIndexConstants.PROP_PROPERTY_INDEX, true);
+ p.session.save();
+ for (int i = 0; i < 600; i++) {
+ index.refresh(false);
+ if (!index.getProperty("reindex").getBoolean()) {
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Run a query and return which index was used.
+ *
+ * @param p the persistence
+ * @param xpath the xpath query
+ * @param expectedIndex the index that is expected to be used
+ * @param expectedResult the expected list of results
+ * @return the index name used
+ */
+ public static void assertQueryUsesIndexAndReturns(Persistence p, String xpath, String expectedIndex,
+ String expectedResult) throws RepositoryException {
+ QueryManager qm = p.session.getWorkspace().getQueryManager();
+ Query q = qm.createQuery("explain " + xpath, "xpath");
+ QueryResult result = q.execute();
+ Row r = result.getRows().nextRow();
+ String plan = r.getValue("plan").getString();
+ if (plan.indexOf(expectedIndex) <= 0) {
+ throw new AssertionError("Index " + expectedIndex + " not used for query " + xpath + ": " + plan);
+ }
+ q = qm.createQuery(xpath, "xpath");
+ NodeIterator it = q.execute().getNodes();
+ ArrayList<String> list = new ArrayList<>();
+ while (it.hasNext()) {
+ Node n = it.nextNode();
+ list.add(n.getPath());
+ }
+ Assert.assertEquals(expectedResult, list.toString());
+ }
+
+ /**
+ * Utility method for debugging.
+ *
+ * @param node the node to print
+ */
+ public static void debugPrintProperties(Node node) throws RepositoryException {
+ PropertyIterator it = node.getProperties();
+ while (it.hasNext()) {
+ Property pr = it.nextProperty();
+ if (pr.isMultiple()) {
+ System.out.println(pr.getName() + " " + Arrays.toString(pr.getValues()));
+ } else {
+ System.out.println(pr.getName() + " " + pr.getValue().getString());
+ }
+ }
+ }
+
+ /**
+ * Check if the /libs node is read-only in this repository.
+ *
+ * @param p the persistence
+ */
+ public static void checkLibsIsReadOnly(Persistence p) throws RepositoryException {
+ // libs is read-only
+ Node libsNode = p.session.getRootNode().getNode("libs");
+ try {
+ libsNode.addNode("illegal");
+ Assert.fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/Persistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/Persistence.java?rev=1869202&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/Persistence.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/Persistence.java Thu Oct 31 07:34:34 2019
@@ -0,0 +1,370 @@
+/*
+ * 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.composite.blueGreen;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.InitialContent;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.composite.CompositeNodeStore;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.atomic.AtomicCounterEditorProvider;
+import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.commit.JcrConflictHandler;
+import org.apache.jackrabbit.oak.plugins.document.bundlor.BundlingConfigInitializer;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.WhiteboardIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.reader.DefaultIndexReaderFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider;
+import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceIndexProvider;
+import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceEditorProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
+import org.apache.jackrabbit.oak.plugins.observation.ChangeCollectorProvider;
+import org.apache.jackrabbit.oak.plugins.version.VersionHook;
+import org.apache.jackrabbit.oak.security.authorization.AuthorizationConfigurationImpl;
+import org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
+import org.apache.jackrabbit.oak.segment.file.FileStore;
+import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
+import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.blob.FileBlobStore;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.query.WhiteboardIndexProvider;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authentication.SystemSubject;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.jetbrains.annotations.NotNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Utility class to open a repository.
+ */
+public class Persistence {
+
+ private static final MountInfoProvider MOUNT_INFO_PROVIDER = createMountInfoProvider();
+
+ private final ArrayList<FileStore> fileStores = new ArrayList<>();
+ private JackrabbitRepository repository;
+ public Session session;
+
+ public static Persistence open(File directory, Config config) throws Exception {
+ Persistence result = new Persistence();
+ FileStore fs = openFileStore(directory, config.blobStore);
+ result.fileStores.add(fs);
+ SegmentNodeStore ns = openSegmentStore(fs);
+ result.repository = openRepsitory(ns, config.indexDir);
+ result.session = result.repository.login(createCredentials());
+ return result;
+ }
+
+ public static Persistence openComposite(File globalDir, File libsDir, Config config) throws Exception {
+ Persistence result = new Persistence();
+ FileStore libsFileStore = openFileStore(libsDir, config.blobStore);
+ result.fileStores.add(libsFileStore);
+ SegmentNodeStore libsStore = openSegmentStore(libsFileStore);
+ FileStore globalFileStore = openFileStore(globalDir, config.blobStore);
+ result.fileStores.add(globalFileStore);
+ SegmentNodeStore globalStore = openSegmentStore(globalFileStore);
+ NodeStore cn = new CompositeNodeStore.Builder(
+ MOUNT_INFO_PROVIDER,
+ globalStore).addMount("libs", libsStore).
+ setPartialReadOnly(true).build();
+ result.repository = openRepsitory(cn, config.indexDir);
+ result.session = result.repository.login(createCredentials());
+ return result;
+ }
+
+ public void close() {
+ session.logout();
+ repository.shutdown();
+ for(FileStore fs : fileStores) {
+ fs.close();
+ }
+ }
+
+ private static MountInfoProvider createMountInfoProvider() {
+ return Mounts.newBuilder()
+ .mount("libs", true, Arrays.asList(
+ // pathsSupportingFragments
+ "/oak:index/*$"
+ ), Arrays.asList(
+ // mountedPaths
+ "/libs",
+ "/apps",
+ "/jcr:system/rep:permissionStore/oak:mount-libs-crx.default"))
+ .build();
+ }
+
+ public static BlobStore getFileBlobStore(File directory) throws IOException {
+ return new FileBlobStore(directory.getAbsolutePath());
+ }
+
+ private static SecurityProvider createSecurityProvider() {
+ Map<String, Object> userConfigMap = new HashMap<>();
+ userConfigMap.put(UserConstants.PARAM_GROUP_PATH, "/home/groups");
+ userConfigMap.put(UserConstants.PARAM_USER_PATH, "/home/users");
+ userConfigMap.put(UserConstants.PARAM_DEFAULT_DEPTH, 1);
+ ConfigurationParameters userConfig = ConfigurationParameters.of(ImmutableMap.of(
+ UserConfiguration.NAME,
+ ConfigurationParameters.of(userConfigMap)));
+ SecurityProvider securityProvider = SecurityProviderBuilder.newBuilder().with(userConfig).build();
+ AuthorizationConfiguration acConfig = securityProvider.getConfiguration(AuthorizationConfiguration.class);
+ ((AuthorizationConfigurationImpl) ((CompositeAuthorizationConfiguration) acConfig).getDefaultConfig()).bindMountInfoProvider(MOUNT_INFO_PROVIDER);
+ return securityProvider;
+ }
+
+ private static FileStore openFileStore(File directory, BlobStore blobStore) throws IOException {
+ try {
+ return FileStoreBuilder
+ .fileStoreBuilder(directory)
+ .withBlobStore(blobStore)
+ .build();
+ } catch (InvalidFileStoreVersionException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private static SegmentNodeStore openSegmentStore(FileStore fileStore) throws IOException {
+ return SegmentNodeStoreBuilders
+ .builder(fileStore)
+ .build();
+ }
+
+ private static JackrabbitRepository openRepsitory(NodeStore nodeStore, File indexDirectory) throws RepositoryException {
+ ExecutorService executorService = Executors.newFixedThreadPool(3);
+ Oak oak = new Oak(nodeStore);
+ oak.withFailOnMissingIndexProvider();
+ InitialContent initialContent = new InitialContent();
+ EditorProvider atomicCounter = new AtomicCounterEditorProvider();
+ SecurityProvider securityProvider = createSecurityProvider();
+ Jcr jcr = new Jcr(oak, false).
+ with(new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ executorService.execute(command);
+ }
+ }).
+ // with(whiteboard)
+ with(initialContent).
+ with(new Content()).
+ with(JcrConflictHandler.createJcrConflictHandler()).
+ with(new VersionHook()).
+ with(securityProvider).
+ with(new NameValidatorProvider()).
+ with(new NamespaceEditorProvider()).
+ with(new TypeEditorProvider()).
+ with(new ConflictValidatorProvider()).
+ with(atomicCounter).
+ // one second delay
+ withAsyncIndexing("async", 1).
+ withAsyncIndexing("fulltext-async", 1);
+ ChangeCollectorProvider changeCollectorProvider = new ChangeCollectorProvider();
+ jcr.with(changeCollectorProvider);
+
+ WhiteboardIndexProvider indexProvider = new WhiteboardIndexProvider();
+ WhiteboardIndexEditorProvider indexEditorProvider = new WhiteboardIndexEditorProvider();
+ boolean fastQueryResultSize = false;
+ jcr.with(indexProvider).
+ with(indexEditorProvider).
+ with("crx.default").
+ withFastQueryResultSize(fastQueryResultSize);
+ IndexTracker indexTracker;
+ IndexCopier indexCopier;
+ try {
+ indexCopier = new IndexCopier(executorService, indexDirectory);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ MountInfoProvider mip = MOUNT_INFO_PROVIDER;
+ DefaultIndexReaderFactory indexReaderFactory = new DefaultIndexReaderFactory(
+ mip, indexCopier);
+ indexTracker = new IndexTracker(indexReaderFactory);
+ LuceneIndexProvider luceneIndexProvider =
+ new LuceneIndexProvider(indexTracker);
+ LuceneIndexEditorProvider luceneIndexEditor =
+ new LuceneIndexEditorProvider(indexCopier, indexTracker, null, null, mip);
+ jcr.with(new PropertyIndexEditorProvider().with(mip)).
+ with(new NodeCounterEditorProvider().with(mip)).
+ with(new PropertyIndexProvider().with(mip)).
+ with(luceneIndexEditor).
+ with((QueryIndexProvider) luceneIndexProvider).
+ with((Observer) luceneIndexProvider).
+ with(new NodeTypeIndexProvider().with(mip)).
+ with(new ReferenceEditorProvider().with(mip)).
+ with(new ReferenceIndexProvider().
+ with(mip)).
+ with(BundlingConfigInitializer.INSTANCE);
+ ContentRepository contentRepository = jcr.createContentRepository();
+ setupPermissions(contentRepository, securityProvider);
+ JackrabbitRepository repository = (JackrabbitRepository) jcr.createRepository();
+ return repository;
+ }
+
+ private static void setupPermissions(ContentRepository repo,
+ SecurityProvider securityProvider) throws RepositoryException {
+ ContentSession cs = null;
+ try {
+ cs = Subject.doAsPrivileged(SystemSubject.INSTANCE, new PrivilegedExceptionAction<ContentSession>() {
+ @Override
+ public ContentSession run() throws Exception {
+ return repo.login(null, null);
+ }
+ }, null);
+
+ Root root = cs.getLatestRoot();
+ AuthorizationConfiguration config = securityProvider.getConfiguration(AuthorizationConfiguration.class);
+ AccessControlManager acMgr = config.getAccessControlManager(root, NamePathMapper.DEFAULT);
+ // protect /oak:index
+ setupPolicy("/" + IndexConstants.INDEX_DEFINITIONS_NAME, acMgr);
+ // protect /jcr:system
+ setupPolicy("/" + JcrConstants.JCR_SYSTEM, acMgr);
+ if (root.hasPendingChanges()) {
+ root.commit();
+ }
+ } catch (PrivilegedActionException | CommitFailedException e) {
+ throw new RepositoryException(e);
+ } finally {
+ if (cs != null) {
+ try {
+ cs.close();
+ } catch (IOException e) {
+ throw new RepositoryException(e);
+ }
+ }
+ }
+ }
+
+ private static void setupPolicy(String path, AccessControlManager acMgr) throws RepositoryException {
+ // only retrieve applicable policies thus leaving the setup untouched once
+ // it has been created and has potentially been modified on an existing
+ // instance
+ AccessControlPolicyIterator it = acMgr.getApplicablePolicies(path);
+ while (it.hasNext()) {
+ AccessControlPolicy policy = it.nextAccessControlPolicy();
+ if (policy instanceof JackrabbitAccessControlList) {
+ JackrabbitAccessControlList acl = (JackrabbitAccessControlList) policy;
+ Privilege[] jcrAll = AccessControlUtils.privilegesFromNames(acMgr, PrivilegeConstants.JCR_ALL);
+ acl.addEntry(EveryonePrincipal.getInstance(), jcrAll, false);
+ acMgr.setPolicy(path, acl);
+ break;
+ }
+ }
+ }
+
+ private static SimpleCredentials createCredentials() {
+ return new SimpleCredentials("admin", "admin".toCharArray());
+ }
+
+ private static class Content implements RepositoryInitializer {
+
+ private static final String FULLTEXT_ASYNC = "fulltext-async";
+ private NodeBuilder index;
+
+ @Override
+ public void initialize(@NotNull NodeBuilder builder) {
+ if (builder.hasChildNode(IndexConstants.INDEX_DEFINITIONS_NAME)) {
+ index = builder.child(IndexConstants.INDEX_DEFINITIONS_NAME);
+ configureGlobalFullTextIndex();
+ }
+ }
+
+ private void configureGlobalFullTextIndex() {
+ String indexName = "lucene";
+ if (!index.hasChildNode(indexName)) {
+ Set<String> INCLUDE_PROPS = ImmutableSet.of("test");
+ IndexDefinitionBuilder indexBuilder = new IndexDefinitionBuilder(index.child(indexName))
+ .codec("Lucene46")
+ .excludedPaths("/libs");
+ indexBuilder.async(FULLTEXT_ASYNC, IndexConstants.INDEXING_MODE_NRT);
+ indexBuilder.aggregateRule("nt:file", "jcr:content");
+ indexBuilder.indexRule("rep:Token");
+ IndexDefinitionBuilder.IndexRule indexRules = indexBuilder.indexRule("nt:base");
+ indexRules.includePropertyTypes("String", "Binary");
+ for (String includeProp : INCLUDE_PROPS) {
+ indexRules.property(includeProp).propertyIndex();
+ }
+ indexBuilder.build();
+ }
+ }
+
+ }
+
+ public static class Config {
+ public BlobStore blobStore;
+ public File indexDir;
+ }
+
+}
+
Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java Thu Oct 31 07:34:34 2019
@@ -85,6 +85,8 @@ import org.apache.jackrabbit.oak.spi.que
import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression;
import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextParser;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.jackrabbit.oak.spi.query.QueryIndex;
import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
@@ -1931,6 +1933,11 @@ public class IndexPlannerTest {
readers.add(new DefaultIndexReader(directory, null, definition.getAnalyzer()));
return readers;
}
+
+ @Override
+ public MountInfoProvider getMountInfoProvider() {
+ return Mounts.defaultMountInfoProvider();
+ }
}
/**
Modified: jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java (original)
+++ jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java Thu Oct 31 07:34:34 2019
@@ -124,4 +124,9 @@ public class ElasticsearchIndex extends
estimators.putIfAbsent(path, new LMSEstimator());
return estimators.get(path);
}
+
+ @Override
+ protected boolean filterReplacedIndexes() {
+ return true;
+ }
}
Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java?rev=1869202&r1=1869201&r2=1869202&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java Thu Oct 31 07:34:34 2019
@@ -87,11 +87,22 @@ public abstract class FulltextIndex impl
protected abstract Predicate<NodeState> getIndexDefinitionPredicate();
protected abstract String getFulltextRequestString(IndexPlan plan, IndexNode indexNode);
+
+ /**
+ * Whether replaced indexes (that is, if a new version of the index is
+ * available) should be filtered out.
+ *
+ * @return true if yes (e.g. in a blue-green deployment model)
+ */
+ protected abstract boolean filterReplacedIndexes();
@Override
public List<IndexPlan> getPlans(Filter filter, List<OrderEntry> sortOrder, NodeState rootState) {
Collection<String> indexPaths = new IndexLookup(rootState, getIndexDefinitionPredicate())
.collectIndexNodePaths(filter);
+ if (filterReplacedIndexes()) {
+ indexPaths = IndexName.filterReplacedIndexes(indexPaths, rootState);
+ }
List<IndexPlan> plans = Lists.newArrayListWithCapacity(indexPaths.size());
for (String path : indexPaths) {
IndexNode indexNode = null;
@@ -115,7 +126,7 @@ public abstract class FulltextIndex impl
}
return plans;
}
-
+
@Override
public double getCost(Filter filter, NodeState root) {
throw new UnsupportedOperationException("Not supported as implementing AdvancedQueryIndex");
Added: 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=1869202&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java Thu Oct 31 07:34:34 2019
@@ -0,0 +1,197 @@
+/*
+ * 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.search.spi.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An index name, which possibly contains two version numbers: the product
+ * version number, and the customer version number.
+ *
+ * The format of an index node name is:
+ * - The name of the index,
+ * - optionally a dash ('-') and the product version number,
+ * - optionally "-custom-" and the customer version number.
+ *
+ * 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> {
+
+ private final static Logger LOG = LoggerFactory.getLogger(IndexName.class);
+
+ // already logged index names
+ private static final HashSet<String> LOGGED_WARN = new HashSet<>();
+ // when LOGGED_WARN will be cleared
+ private static long nextLogWarnClear;
+
+ private final String nodeName;
+ private final String baseName;
+ private final boolean isVersioned;
+ private final int productVersion;
+ private final int customerVersion;
+ private final boolean isLegal;
+
+ /**
+ * Parse the node name. Both node names with version and without version are
+ * supported.
+ *
+ * @param nodeName the node name (starting from root; e.g. "/oak:index/lucene")
+ * @return the index name object
+ */
+ public static IndexName parse(final String nodeName) {
+ String baseName = nodeName;
+ int index = baseName.lastIndexOf('-');
+ if (index < 0) {
+ return new IndexName(nodeName, true);
+ }
+ String last = baseName.substring(index + 1);
+ baseName = baseName.substring(0, index);
+ try {
+ int v1 = Integer.parseInt(last);
+ if (!baseName.endsWith("-custom")) {
+ return new IndexName(nodeName, baseName, v1, 0);
+ }
+ baseName = baseName.substring(0,
+ baseName.length() - "-custom".length());
+ index = baseName.lastIndexOf('-');
+ if (index < 0) {
+ return new IndexName(nodeName, baseName, 0, v1);
+ }
+ last = baseName.substring(index + 1);
+ baseName = baseName.substring(0, index);
+ int v2 = Integer.parseInt(last);
+ return new IndexName(nodeName, baseName, v2, v1);
+ } catch (NumberFormatException e) {
+ long now = System.currentTimeMillis();
+ if (nextLogWarnClear < now) {
+ LOGGED_WARN.clear();
+ // clear again each 5 minutes
+ nextLogWarnClear = now + 5 * 60 * 1000;
+ }
+ if (LOGGED_WARN.add(nodeName)) {
+ LOG.warn("Index name format error: " + nodeName);
+ }
+ return new IndexName(nodeName, false);
+ }
+ }
+
+ private IndexName(String nodeName, boolean isLegal) {
+ // not versioned
+ this.nodeName = nodeName;
+ this.baseName = nodeName;
+ this.isVersioned = false;
+ this.productVersion = 0;
+ this.customerVersion = 0;
+ this.isLegal = isLegal;
+ }
+
+ private IndexName(String nodeName, String baseName, int productVersion, int customerVersion) {
+ // versioned
+ this.nodeName = nodeName;
+ this.baseName = baseName;
+ this.isVersioned = true;
+ this.productVersion = productVersion;
+ this.customerVersion = customerVersion;
+ this.isLegal = true;
+ }
+
+ public String toString() {
+ return nodeName +
+ " base=" + baseName +
+ (isVersioned ? " versioned": "") +
+ " product=" + productVersion +
+ " custom=" + customerVersion +
+ (isLegal ? "" : " illegal");
+ }
+
+ @Override
+ public int compareTo(IndexName o) {
+ int comp = baseName.compareTo(o.baseName);
+ if (comp != 0) {
+ return comp;
+ }
+ comp = Integer.compare(productVersion, o.productVersion);
+ if (comp != 0) {
+ return comp;
+ }
+ return Integer.compare(customerVersion, o.customerVersion);
+ }
+
+ /**
+ * Filter out index that are replaced by another index with the same base
+ * name but newer version.
+ *
+ * Indexes without a version number in the name are always used, except if
+ * there is an active index with the same base name but a newer version.
+ *
+ * Active indexes have a hidden ":oak:mount-" node, which means they are
+ * indexed in the read-only node store.
+ *
+ * @param indexPaths the set of index paths
+ * @param rootState the root node state (used to find hidden nodes)
+ * @return the filtered list
+ */
+ public static Collection<String> filterReplacedIndexes(Collection<String> indexPaths, NodeState rootState) {
+ HashMap<String, IndexName> latestVersions = new HashMap<String, IndexName>();
+ for (String p : indexPaths) {
+ IndexName indexName = IndexName.parse(p);
+ if (indexName.isVersioned) {
+ // which might not be a good idea - instead, it should check if the composite node store is used
+ // (but how?)
+ if (!isIndexActive(p, rootState)) {
+ // the index is inactive, so not used
+ continue;
+ }
+ }
+ IndexName stored = latestVersions.get(indexName.baseName);
+ if (stored == null || stored.compareTo(indexName) < 0) {
+ // no old version, or old version is smaller: replace
+ latestVersions.put(indexName.baseName, indexName);
+ }
+ }
+ ArrayList<String> result = new ArrayList<>(latestVersions.size());
+ for (IndexName n : latestVersions.values()) {
+ result.add(n.nodeName);
+ }
+ return result;
+ }
+
+ private static boolean isIndexActive(String indexPath, NodeState rootState) {
+ NodeState indexNode = rootState;
+ for(String e : PathUtils.elements(indexPath)) {
+ indexNode = indexNode.getChildNode(e);
+ }
+ for(String c : indexNode.getChildNodeNames()) {
+ if (c.startsWith(":oak:mount-")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java?rev=1869202&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java Thu Oct 31 07:34:34 2019
@@ -0,0 +1,81 @@
+/*
+ * 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.search.spi.query;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Test the IndexName class
+ */
+public class IndexNameTest {
+
+ @Test
+ public void parse() {
+ assertEquals("/lucene base=/lucene product=0 custom=0",
+ IndexName.parse("/lucene").toString());
+ assertEquals("/lucene-1 base=/lucene versioned product=1 custom=0",
+ IndexName.parse("/lucene-1").toString());
+ assertEquals("/lucene-2 base=/lucene versioned product=2 custom=0",
+ IndexName.parse("/lucene-2").toString());
+ assertEquals("/lucene-custom-3 base=/lucene versioned product=0 custom=3",
+ IndexName.parse("/lucene-custom-3").toString());
+ assertEquals("/lucene-4-custom-5 base=/lucene versioned product=4 custom=5",
+ IndexName.parse("/lucene-4-custom-5").toString());
+ assertEquals("/lucene-12-custom-34 base=/lucene versioned product=12 custom=34",
+ IndexName.parse("/lucene-12-custom-34").toString());
+ // illegal
+ assertEquals("/lucene-abc base=/lucene-abc product=0 custom=0 illegal",
+ IndexName.parse("/lucene-abc").toString());
+ assertEquals("/lucene-abc-custom-2 base=/lucene-abc-custom-2 product=0 custom=0 illegal",
+ IndexName.parse("/lucene-abc-custom-2").toString());
+ }
+
+ @Test
+ public void compare() {
+ IndexName p0 = IndexName.parse("/lucene");
+ IndexName p0a = IndexName.parse("/lucene-0");
+ IndexName p0b = IndexName.parse("/lucene-0-custom-0");
+ IndexName p0c1 = IndexName.parse("/lucene-custom-1");
+ IndexName p0c1a = IndexName.parse("/lucene-0-custom-1");
+ IndexName p1 = IndexName.parse("/lucene-1");
+ IndexName p1c1 = IndexName.parse("/lucene-1-custom-1");
+ IndexName p1c2 = IndexName.parse("/lucene-1-custom-2");
+
+ assertTrue(p0.compareTo(p0a) == 0);
+ assertTrue(p0.compareTo(p0b) == 0);
+ assertTrue(p0a.compareTo(p0b) == 0);
+ assertTrue(p0c1.compareTo(p0c1a) == 0);
+
+ assertTrue(p0.compareTo(p0c1) < 0);
+ assertTrue(p0c1.compareTo(p1) < 0);
+ assertTrue(p1.compareTo(p1c1) < 0);
+ assertTrue(p1c1.compareTo(p1c2) < 0);
+
+ IndexName a = IndexName.parse("/luceneA");
+ IndexName b = IndexName.parse("/luceneB");
+ IndexName c = IndexName.parse("/luceneC");
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(c) < 0);
+
+ }
+
+}