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 2020/12/17 14:39:33 UTC
svn commit: r1884554 - in /jackrabbit/oak/trunk:
oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/
oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/
Author: thomasm
Date: Thu Dec 17 14:39:33 2020
New Revision: 1884554
URL: http://svn.apache.org/viewvc?rev=1884554&view=rev
Log:
OAK-9301 Automatically pick a merged index
Modified:
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-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java
Modified: 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=1884554&r1=1884553&r2=1884554&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/CustomizedIndexTest.java Thu Dec 17 14:39:33 2020
@@ -21,6 +21,8 @@ package org.apache.jackrabbit.oak.compos
import java.io.File;
import java.io.IOException;
+import javax.jcr.Node;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -34,13 +36,13 @@ public class CustomizedIndexTest {
@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();
@@ -51,73 +53,120 @@ public class CustomizedIndexTest {
compositeLibs1();
initLibs2();
compositeLibs2();
+ compositeWithMergedIndex();
}
-
+
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",
+ 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.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",
+ 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",
+
+ // the new index must be used in the new version (with libs2)
+ 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)
+
+ // the new index must not be used in the old version (with libs1)
p = Persistence.openComposite(globalDir, libs1Dir, config);
- IndexUtils.assertQueryUsesIndexAndReturns(p,
- "/jcr:root//*[@foo] order by @jcr:path",
- "test-1",
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-1",
"[/content/test, /libs/test]");
p.close();
}
-
+
+ private void compositeWithMergedIndex() throws Exception {
+ // a new _merged_ index must be used by the new version (with libs2)
+ // but it won't contain the libs part (as that's not indexed)
+ Persistence p = Persistence.openComposite(globalDir, libs2Dir, config);
+ Node n = IndexUtils.createIndex(p, "test-2-custom-1", "foo", 10);
+ n.setProperty("merges", new String[]{"/oak:index/test-2"});
+ n.getSession().save();
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-2-custom-1",
+ "[/content/test]");
+ // no let it point to a non-existing node: the index should be used
+ n.setProperty("merges", new String[]{"/oak:index/test-does-not-exist"});
+ n.getSession().save();
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-2-custom-1",
+ "[/content/test]");
+ p.close();
+
+ // the merged index is not used in the old version (with libs1)
+ // because the index test-2 is not active
+ p = Persistence.openComposite(globalDir, libs1Dir, config);
+ n = p.session.getNode("/oak:index/test-2-custom-1");
+ n.setProperty("merges", new String[]{"/oak:index/test-2"});
+ n.getSession().save();
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-1",
+ "[/content/test, /libs/test]");
+ // no let it point to a non-existing node: the index should be used
+ n.setProperty("merges", new String[]{"/oak:index/test-does-not-exist"});
+ n.getSession().save();
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo] order by @jcr:path",
+ "test-2-custom-1",
+ "[/content/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",
+ 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",
+ IndexUtils.assertQueryUsesIndexAndReturns(p,
+ "/jcr:root//*[@foo]",
+ "test-2",
"[/libs/test2]");
- p.close();
+ p.close();
}
-
+
private void createFolders() throws IOException {
globalDir = tempDir.newFolder("global");
libs1Dir = tempDir.newFolder("libs1");
@@ -125,5 +174,5 @@ public class CustomizedIndexTest {
datastoreDir = tempDir.newFolder("datastore");
indexDir = tempDir.newFolder("index");
}
-
+
}
Modified: 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=1884554&r1=1884553&r2=1884554&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/composite/blueGreen/IndexUtils.java Thu Dec 17 14:39:33 2020
@@ -47,19 +47,20 @@ 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)
+ * @return the index definition node
*/
- public static void createIndex(Persistence p, String indexName, String propertyName, double cost) throws RepositoryException {
+ public static Node 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,
+ index.setProperty(IndexConstants.ASYNC_PROPERTY_NAME,
new String[] { "async", "nrt" });
index.setProperty(FulltextIndexConstants.COST_PER_EXECUTION, cost);
// index.setProperty("excludedPaths", "/jcr:system");
@@ -81,11 +82,12 @@ public class IndexUtils {
// ignore
}
}
+ return index;
}
-
+
/**
* 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
@@ -111,10 +113,10 @@ public class IndexUtils {
}
Assert.assertEquals(expectedResult, list.toString());
}
-
+
/**
* Utility method for debugging.
- *
+ *
* @param node the node to print
*/
public static void debugPrintProperties(Node node) throws RepositoryException {
@@ -131,7 +133,7 @@ public class IndexUtils {
/**
* Check if the /libs node is read-only in this repository.
- *
+ *
* @param p the persistence
*/
public static void checkLibsIsReadOnly(Persistence p) throws RepositoryException {
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=1884554&r1=1884553&r2=1884554&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 Thu Dec 17 14:39:33 2020
@@ -24,7 +24,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,19 +35,19 @@ 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,
+ *
+ * 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).
*/
public 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
@@ -56,11 +59,11 @@ public class IndexName implements Compar
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
*/
@@ -77,7 +80,7 @@ public class IndexName implements Compar
if (!baseName.endsWith("-custom")) {
return new IndexName(nodeName, baseName, v1, 0);
}
- baseName = baseName.substring(0,
+ baseName = baseName.substring(0,
baseName.length() - "-custom".length());
index = baseName.lastIndexOf('-');
if (index < 0) {
@@ -100,7 +103,7 @@ public class IndexName implements Compar
return new IndexName(nodeName, false);
}
}
-
+
private IndexName(String nodeName, boolean isLegal) {
// not versioned
this.nodeName = nodeName;
@@ -120,16 +123,16 @@ public class IndexName implements Compar
this.customerVersion = customerVersion;
this.isLegal = true;
}
-
+
public String toString() {
- return nodeName +
- " base=" + baseName +
- (isVersioned ? " versioned": "") +
- " product=" + productVersion +
+ return nodeName +
+ " base=" + baseName +
+ (isVersioned ? " versioned": "") +
+ " product=" + productVersion +
" custom=" + customerVersion +
(isLegal ? "" : " illegal");
}
-
+
@Override
public int compareTo(IndexName o) {
int comp = baseName.compareTo(o.baseName);
@@ -187,13 +190,13 @@ public class IndexName implements Compar
/**
* 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
@@ -228,6 +231,8 @@ public class IndexName implements Compar
}
private static boolean isIndexActive(String indexPath, NodeState rootState) {
+ // An index is active if it has a hidden child node that starts with ":oak:mount-",
+ // OR if it is an active merged index
NodeState indexNode = rootState;
for(String e : PathUtils.elements(indexPath)) {
indexNode = indexNode.getChildNode(e);
@@ -237,7 +242,39 @@ public class IndexName implements Compar
return true;
}
}
- return false;
+ return isIndexActiveMerged(indexNode, rootState);
+ }
+
+ private static boolean isIndexActiveMerged(NodeState indexNode, NodeState rootState) {
+ // An index is an active merged index if it has the property "merges",
+ // and that property points to index definitions,
+ // and each of those indexes is either active, disabled, or removed.
+ PropertyState ps = indexNode.getProperty("merges");
+ if (ps == null) {
+ return false;
+ }
+ if (ps.getType() != Type.STRING && ps.getType() != Type.STRINGS) {
+ return false;
+ }
+ for (int i = 0; i < ps.count(); i++) {
+ String merges = ps.getValue(Type.STRING, i);
+ NodeState mergeNode = rootState;
+ for (String e : PathUtils.elements(merges)) {
+ mergeNode = mergeNode.getChildNode(e);
+ }
+ if (!mergeNode.exists()) {
+ continue;
+ }
+ String indexType = mergeNode.getString(IndexConstants.TYPE_PROPERTY_NAME);
+ if (IndexConstants.TYPE_DISABLED.equals(indexType)) {
+ continue;
+ }
+ if (isIndexActive(merges, rootState)) {
+ continue;
+ }
+ return false;
+ }
+ return true;
}
public String getNodeName() {
@@ -263,5 +300,5 @@ public class IndexName implements Compar
public boolean isLegal() {
return isLegal;
}
-
+
}
\ No newline at end of file