diff --git a/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java b/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java index 3d687384f48..c8ee6e5649f 100644 --- a/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java +++ b/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexName.java @@ -233,16 +233,21 @@ public String nextCustomizedName() { 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); - } - for(String c : indexNode.getChildNodeNames()) { - if (c.startsWith(":oak:mount-")) { - return true; + try { + 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 isIndexActiveMerged(indexNode, rootState); + } catch (StackOverflowError e) { + LOG.error("Fail to check index activeness for {} due to StackOverflowError", indexPath, e); + return true; } - return isIndexActiveMerged(indexNode, rootState); } private static boolean isIndexActiveMerged(NodeState indexNode, NodeState rootState) { diff --git a/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java b/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java index c39ab80320a..589fee6589f 100644 --- a/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java +++ b/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNameTest.java @@ -20,8 +20,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE; +import org.apache.jackrabbit.oak.commons.junit.LogCustomizer; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeState; import org.junit.Test; +import org.slf4j.event.Level; +import java.util.ArrayList; /** * Test the IndexName class @@ -30,22 +37,22 @@ public class IndexNameTest { @Test public void parse() { - assertEquals("/lucene base=/lucene product=0 custom=0", + assertEquals("/lucene base=/lucene product=0 custom=0", IndexName.parse("/lucene").toString()); - assertEquals("/lucene-1 base=/lucene versioned product=1 custom=0", + 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", + 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", + 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", + 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", + 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", + 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", + assertEquals("/lucene-abc-custom-2 base=/lucene-abc-custom-2 product=0 custom=0 illegal", IndexName.parse("/lucene-abc-custom-2").toString()); } @@ -59,23 +66,49 @@ public void compare() { 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); - + } + @Test + public void recursiveActive() { + LogCustomizer lc = LogCustomizer.forLogger(IndexName.class) + .enable(Level.ERROR) + .filter(Level.ERROR) + .create(); + + NodeBuilder builder = EMPTY_NODE.builder(); + NodeBuilder luceneOneBuilder = builder.child("lucene-1"); + NodeBuilder luceneTwoBuilder = builder.child("lucene-2"); + luceneOneBuilder.setProperty("merges", "lucene-1"); + luceneTwoBuilder.setProperty("merges", "lucene-2"); + NodeState base = builder.getNodeState(); + ArrayList indexPaths = new ArrayList<>(); + indexPaths.add("lucene-1"); + + try { + lc.starting(); + IndexName.filterReplacedIndexes(indexPaths, base, true); + assertTrue("StackOverflowError should be caught", lc.getLogs().contains("Fail to check index activeness for lucene-1 due to StackOverflowError")); + } catch (StackOverflowError e) { + fail("should not run into StackOverflowError exception"); + } finally { + lc.finished(); + } + } } diff --git a/oak-search/src/test/resources/logback-test.xml b/oak-search/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..5b394d9fbea --- /dev/null +++ b/oak-search/src/test/resources/logback-test.xml @@ -0,0 +1,38 @@ + + + + + + %date{HH:mm:ss.SSS} %-5level %-40([%thread] %F:%L) %msg%n + + + + + target/unit-tests.log + + %date{HH:mm:ss.SSS} %-5level %-40([%thread] %F:%L) %msg%n + + + + + + + + + +