This is an automated email from the ASF dual-hosted git repository.
baedke pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new 0deaad5013 OAK-11697: Indexing / query limit / traversal error:
improve diagnostics (#2626)
0deaad5013 is described below
commit 0deaad501396efaabc5f245a6bfeefd9c75b84d2
Author: mbaedke <[email protected]>
AuthorDate: Wed Feb 18 17:17:32 2026 +0100
OAK-11697: Indexing / query limit / traversal error: improve diagnostics
(#2626)
Extended logging and error message.
---------
Co-authored-by: Thomas Mueller <[email protected]>
---
.../org/apache/jackrabbit/oak/query/QueryImpl.java | 45 ++++++++++++++++++++--
.../apache/jackrabbit/oak/jcr/query/QueryTest.java | 38 ++++++++++++++++++
2 files changed, 80 insertions(+), 3 deletions(-)
diff --git
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
index 3f08b4fae4..87747fbb7b 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
@@ -14,6 +14,12 @@
package org.apache.jackrabbit.oak.query;
import static java.util.Objects.requireNonNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_DISABLED;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
import static
org.apache.jackrabbit.oak.query.ast.AstElementFactory.copyElementAndCheckReference;
import java.math.BigInteger;
@@ -32,9 +38,11 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.api.Result.SizePrecision;
import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.namepath.JcrPathParser;
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
@@ -1257,7 +1265,7 @@ public class QueryImpl implements Query {
@Override
public void verifyNotPotentiallySlow() {
if (potentiallySlowTraversalQuery) {
- QueryOptions.Traversal traversal = queryOptions.traversal;
+ Traversal traversal = queryOptions.traversal;
if (traversal == Traversal.DEFAULT) {
// use the (configured) default
traversal = settings.getFailTraversal() ? Traversal.FAIL :
Traversal.WARN;
@@ -1265,8 +1273,7 @@ public class QueryImpl implements Query {
// explicitly set in the query
traversal = queryOptions.traversal;
}
- String caller =
IndexUtils.getCaller(settings.getIgnoredClassNamesInCallTrace());
- String message = "Traversal query (query without index): " +
statement + "; called by " + caller + "; consider creating an index";
+ String message = createTraversalWarningMessage(traversal);
switch (traversal) {
case DEFAULT:
// not possible (changed to either FAIL or WARN above)
@@ -1285,6 +1292,38 @@ public class QueryImpl implements Query {
}
}
}
+
+ private String createTraversalWarningMessage(Traversal traversal) {
+ String caller =
IndexUtils.getCaller(settings.getIgnoredClassNamesInCallTrace());
+ String message = "Traversal query (query without index): " + statement
+ "; called by " + caller + "; consider creating an index";
+ if (traversal == Traversal.FAIL || traversal == Traversal.WARN &&
!potentiallySlowTraversalQueryLogged) {
+ Set<String> reindex = getNamesOfReindexingIndexes();
+ message += "\n\nExecution plan:\n" + getPlan();
+ if (!reindex.isEmpty()) {
+ String reindexNames = reindex.stream().map(name -> name +
",").collect(Collectors.joining());
+ message += "\n\nNote that the following indexes were
re-indexing at query time:\n"
+ + reindexNames.substring(0, reindexNames.length() - 1);
+ }
+ }
+ return message;
+ }
+
+ private Set<String> getNamesOfReindexingIndexes() {
+ Set<String> reindex = new HashSet<>();
+ Iterable<Tree> indexes = context.getRoot().getTree("/" +
INDEX_DEFINITIONS_NAME).getChildren();
+ for (Tree index : indexes) {
+ String name = index.getName();
+ PropertyState primaryType = index.getProperty(JCR_PRIMARYTYPE);
+ if (primaryType != null &&
INDEX_DEFINITIONS_NODE_TYPE.equals(primaryType.getValue(Type.STRING))) {
+ PropertyState reindexProp =
index.getProperty(REINDEX_PROPERTY_NAME);
+ PropertyState typeProp = index.getProperty(TYPE_PROPERTY_NAME);
+ if (reindexProp != null && reindexProp.getValue(Type.BOOLEAN)
&& typeProp != null && !TYPE_DISABLED.equals(typeProp.getValue(Type.STRING))) {
+ reindex.add(name);
+ }
+ }
+ }
+ return reindex;
+ }
private List<OrderEntry> getSortOrder(FilterImpl filter) {
if (orderings == null) {
diff --git
a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
index 04b383957c..214bd94d0a 100644
--- a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
+++ b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
@@ -18,6 +18,10 @@
*/
package org.apache.jackrabbit.oak.jcr.query;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+import static org.apache.jackrabbit.oak.spi.commit.CommitInfo.EMPTY;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -41,6 +45,7 @@ import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
+import javax.jcr.Workspace;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.query.InvalidQueryException;
import javax.jcr.query.Query;
@@ -60,6 +65,8 @@ import org.apache.jackrabbit.oak.commons.json.JsonObject;
import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
import org.apache.jackrabbit.oak.fixture.NodeStoreFixture;
import org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.junit.Ignore;
import org.junit.Test;
@@ -138,6 +145,37 @@ public class QueryTest extends AbstractRepositoryTest {
assertEquals(90, count);
}
+ @Test
+ public void traversalExtendedDiagnosis() throws Exception {
+ Session session = getAdminSession();
+ Workspace workspace = session.getWorkspace();
+ NodeBuilder rootBuilder = getNodeStore().getRoot().builder();
+ createIndexDefinition(
+ rootBuilder.child(INDEX_DEFINITIONS_NAME), "foo", true, false,
+ Set.of("foo"), null);
+ getNodeStore().merge(rootBuilder, EmptyHook.INSTANCE, EMPTY);
+ session.refresh(true);
+ rootBuilder.child("a").setProperty("foo", "abc");
+ //set reindex=true without a CommitHook to simulate an ongoing
re-indexing process.
+
rootBuilder.child(INDEX_DEFINITIONS_NAME).child("foo").setProperty(REINDEX_PROPERTY_NAME,
true);
+ getNodeStore().merge(rootBuilder, EmptyHook.INSTANCE, EMPTY);
+ session.refresh(true);
+ Node foo = session.getNode("/" +
INDEX_DEFINITIONS_NAME).getNode("foo");
+ assertTrue(foo.getProperty(REINDEX_PROPERTY_NAME).getBoolean());
+ Query query = workspace.getQueryManager().createQuery("select * from
[nt:base] where [x] = 1 or [y] = 2 option(traversal fail)", Query.JCR_SQL2);
+ try {
+ query.execute();
+ fail("traversing query should not succeed");
+ } catch (RepositoryException e) {
+ String message = e.getMessage();
+ assertTrue(message.contains("Traversal query (query without
index)"));
+ assertTrue(message.contains("Execution plan"));
+ assertTrue(message.contains("[nt:base] as [nt:base] /* traverse"));
+ assertTrue(message.contains("Note that the following indexes were
re-indexing at query time"));
+ assertTrue(message.contains("foo"));
+ }
+ }
+
@Test
public void traversalOption() throws Exception {
Session session = getAdminSession();