This is an automated email from the ASF dual-hosted git repository.

fortino 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 e8af772  OAK-9624 print the name of the calling class invoking a query 
in some cases (#420)
e8af772 is described below

commit e8af772537fe0fa800ac112dccb916689cc96d02
Author: Jörg Hoh <[email protected]>
AuthorDate: Fri Nov 26 12:19:39 2021 +0100

    OAK-9624 print the name of the calling class invoking a query in some cases 
(#420)
    
    * OAK-9624 print the name of the calling class invoking a query in some 
cases
    
    * implement PR feedback
    
    * implement PR feedback
    
    * add unit test
---
 .../oak/api/jmx/QueryEngineSettingsMBean.java      | 18 ++++++++++++
 .../jackrabbit/oak/api/jmx/package-info.java       |  2 +-
 .../main/java/org/apache/jackrabbit/oak/Oak.java   |  8 +++++
 .../jackrabbit/oak/plugins/index/Cursors.java      |  4 ++-
 .../jackrabbit/oak/plugins/index/IndexUtils.java   | 34 ++++++++++++++++++++++
 .../plugins/index/property/PropertyIndexPlan.java  |  8 +++--
 .../strategy/ContentMirrorStoreStrategy.java       |  5 +++-
 .../jackrabbit/oak/query/QueryEngineSettings.java  | 14 +++++++++
 .../oak/query/QueryEngineSettingsService.java      | 10 +++++++
 .../oak/plugins/index/IndexUtilsTest.java          | 16 ++++++++++
 .../property/PropertyIndexDeprecatedTest.java      |  2 +-
 .../jackrabbit/oak/spi/query/QueryLimits.java      | 11 ++++++-
 .../jackrabbit/oak/spi/query/package-info.java     |  2 +-
 13 files changed, 125 insertions(+), 9 deletions(-)

diff --git 
a/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
 
b/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
index 9177e46..6a7db82 100644
--- 
a/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
+++ 
b/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.api.jmx;
 
+import org.jetbrains.annotations.NotNull;
 import org.osgi.annotation.versioning.ProviderType;
 
 @ProviderType
@@ -140,4 +141,21 @@ public interface QueryEngineSettingsMBean {
     @Description("Get the query validator data as a JSON string.")
     String getQueryValidatorJson();
 
+    /**
+     * Set or remove java package/class names which are ignored from finding 
the 
+     * invoking class for queries.
+     * 
+     * It can be either Java package names or fully-qualified class names 
(package + class name).
+     * 
+     * @param classNames the class names to be ignored.
+     */
+    @Description("Set or remove Java package / fully qualified class names to 
ignore in Call Trace analysis")
+    void setIgnoredClassNamesInCallTrace(
+            @Description("package or fully qualified class names")
+            @Name("class names")
+            @NotNull String[] classNames);
+    
+//    @Description("Get the Java package / fully qualified class names to 
ignore when finding the caller of query")
+    @NotNull
+    String[] getIgnoredClassNamesInCallTrace();
 }
diff --git 
a/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java 
b/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
index 870e73d..38a9f0c 100644
--- a/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
+++ b/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("4.10.0")
+@Version("4.11.0")
 package org.apache.jackrabbit.oak.api.jmx;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
index d5143cb..1fbc79f 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
@@ -974,6 +974,14 @@ public class Oak {
         void setFullTextComparisonWithoutIndex(boolean 
fullTextComparisonWithoutIndex) {
             
this.settings.setFullTextComparisonWithoutIndex(fullTextComparisonWithoutIndex);
         }
+
+        public void setIgnoredClassNamesInCallTrace(@NotNull String[] 
packageNames) {
+            settings.setIgnoredClassNamesInCallTrace(packageNames);
+        }
+
+        public @NotNull String[] getIgnoredClassNamesInCallTrace() {
+            return settings.getIgnoredClassNamesInCallTrace();
+        }
     }
 
     public static class OakDefaultComponents {
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/Cursors.java 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/Cursors.java
index 0cca8c7..3373c75 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/Cursors.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/Cursors.java
@@ -339,7 +339,9 @@ public class Cursors {
                     readCount++;
                     if (readCount % 1000 == 0) {
                         FilterIterators.checkReadLimit(readCount, settings);
-                        LOG.warn("Traversed " + readCount + " nodes with 
filter " + filter + "; consider creating an index or changing the query");
+                        String caller = 
IndexUtils.getCaller(this.settings.getIgnoredClassNamesInCallTrace());
+                        LOG.warn("Traversed {} nodes with filter {} called by 
{}; consider creating an index or changing the query" , 
+                                readCount, filter, caller);
                     }
 
                     NodeState node = entry.getNodeState();
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
index e104119..b338a6b 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
@@ -33,6 +33,7 @@ import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.UNIQUE_PROP
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Stream;
 
 import javax.jcr.RepositoryException;
 
@@ -241,4 +242,37 @@ public final class IndexUtils {
         }
         return null;
     }
+
+    /**
+     * Retrieves the calling class and method from the call stack; this is 
determined by unwinding
+     * the stack until it finds a combination of full qualified classname + 
method (separated by ".") which
+     * do not start with any of the values provided by the ignoredJavaPackages 
parameters. If the provided
+     * parameters cover all stack frames, the whole query is considered to be 
internal, where the 
+     * actual caller doesn't matter (or cannot be determined clearly). In this 
case a short message
+     * indicating this is returned.
+     *
+     * If the ignoredJavaPackages parameter is null or empty, the caller is 
not looked up, but
+     * instead it is assumed, that the feature is not configured; in that case 
a short messages
+     * is returned indicating that the feature is not configured.
+     *
+     * @param ignoredJavaPackages the java packages or class names
+     * @return the calling class or another non-null value
+     */
+    @NotNull
+    public static String getCaller(@Nullable String[] ignoredJavaPackages) {
+        if (ignoredJavaPackages == null || ignoredJavaPackages.length == 0) {
+            return "(<function not configured>)";
+        }
+
+        // With java9 we would use 
https://docs.oracle.com/javase/9/docs/api/java/lang/StackWalker.html
+        final StackTraceElement[] callStack = 
Thread.currentThread().getStackTrace();
+        for (StackTraceElement stackFrame : callStack) {
+            final String classAndMethod = stackFrame.getClassName() + "." + 
stackFrame.getMethodName();
+            if 
(Stream.of(ignoredJavaPackages).noneMatch(classAndMethod::startsWith)) {
+                return classAndMethod;
+            }
+        }
+        // if every element is ignored, we assume it's an internal request
+        return "(internal)";
+    }
 }
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
index d6d1055..10664bd 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexPlan.java
@@ -30,6 +30,7 @@ import java.util.Set;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.index.Cursors;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
 import 
org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
 import org.apache.jackrabbit.oak.spi.filter.PathFilter;
 import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
@@ -205,11 +206,12 @@ public class PropertyIndexPlan {
     }
 
     Cursor execute() {
+        QueryLimits settings = filter.getQueryLimits();
         if (deprecated) {
-            LOG.warn("This index is deprecated: {}; it is used for query {}. " 
+ 
-                    "Please change the query or the index definitions.", name, 
filter);
+            final String caller = 
IndexUtils.getCaller(settings.getIgnoredClassNamesInCallTrace());
+            LOG.warn("This index is deprecated: {}; it is used for query {} 
called by {}. " +
+                    "Please change the query or the index definitions.", name, 
filter, caller);
         }
-        QueryLimits settings = filter.getQueryLimits();
         List<Iterable<String>> iterables = Lists.newArrayList();
         for (IndexStoreStrategy s : strategies) {
             iterables.add(s.query(filter, name, definition, values));
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
index 3b62abc..403533f 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
@@ -28,6 +28,7 @@ import java.util.Set;
 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.IndexUtils;
 import org.apache.jackrabbit.oak.plugins.index.counter.ApproximateCounter;
 import org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditor;
 import org.apache.jackrabbit.oak.plugins.index.counter.jmx.NodeCounter;
@@ -456,7 +457,9 @@ public class ContentMirrorStoreStrategy implements 
IndexStoreStrategy {
                         readCount++;
                         if (readCount % TRAVERSING_WARN == 0) {
                             FilterIterators.checkReadLimit(readCount, 
settings);
-                            LOG.warn("Index-Traversed {} nodes ({} index 
entries) using index {} with filter {}", readCount, intermediateNodeReadCount, 
indexName, filter);
+                            String caller = 
IndexUtils.getCaller(settings.getIgnoredClassNamesInCallTrace());
+                            LOG.warn("Index-Traversed {} nodes ({} index 
entries) using index {} with filter {}, caller {}", 
+                                    readCount, intermediateNodeReadCount, 
indexName, filter, caller);
                         }
                         return;
                     } else {
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
index 61a4447..119488c 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import java.util.Arrays;
+
 import org.apache.jackrabbit.oak.api.StrictPathRestriction;
 import org.apache.jackrabbit.oak.api.jmx.QueryEngineSettingsMBean;
 import org.apache.jackrabbit.oak.query.stats.QueryStatsMBean;
@@ -25,6 +27,7 @@ import 
org.apache.jackrabbit.oak.query.stats.QueryStatsMBeanImpl;
 import org.apache.jackrabbit.oak.query.stats.QueryStatsReporter;
 import org.apache.jackrabbit.oak.spi.query.QueryLimits;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Settings of the query engine.
@@ -88,6 +91,8 @@ public class QueryEngineSettings implements 
QueryEngineSettingsMBean, QueryLimit
 
     private final QueryValidator queryValidator = new QueryValidator();
 
+    private String[] classNamesIgnoredInCallTrace = new String[] {};
+
     public QueryEngineSettings() {
         statisticsProvider = StatisticsProvider.NOOP;
     }
@@ -182,6 +187,14 @@ public class QueryEngineSettings implements 
QueryEngineSettingsMBean, QueryLimit
     public QueryValidator getQueryValidator() {
         return queryValidator;
     }
+    
+    public void setIgnoredClassNamesInCallTrace(@NotNull String[] 
packageNames) {
+        classNamesIgnoredInCallTrace = packageNames;
+    }
+    
+    public @NotNull String[] getIgnoredClassNamesInCallTrace() {
+        return classNamesIgnoredInCallTrace;
+    }
 
     @Override
     public String toString() {
@@ -192,6 +205,7 @@ public class QueryEngineSettings implements 
QueryEngineSettingsMBean, QueryLimit
                 ", fullTextComparisonWithoutIndex=" + 
fullTextComparisonWithoutIndex +
                 ", sql2Optimisation=" + sql2Optimisation +
                 ", fastQuerySize=" + fastQuerySize +
+                ", classNamesIgnoredInCallTrace=" + 
Arrays.toString(classNamesIgnoredInCallTrace) +
                 '}';
     }
     
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
index 7068491..f52542a 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
@@ -77,6 +77,14 @@ public class QueryEngineSettingsService {
                         "the queryPaths of the index is taken into account."
         )
         String getStrictPathRestrictionsForIndexes() default 
DISABLED_STRICT_PATH_RESTRICTION;
+        
+        @AttributeDefinition(
+                name="Fully qualified class names to ignore when finding 
caller",
+                description="If non-empty the query engine logs the query 
statement plus the java package "
+                        + "which executed this query. This java package is the 
first package in the call trace "
+                        + "which does not  start with any of the provided 
fully qualified class names (packagename + classname)"
+                )
+        String[] ignoredClassNamesInCallTrace() default {};
 
     }
 
@@ -122,6 +130,8 @@ public class QueryEngineSettingsService {
             logMsg(QUERY_FAIL_TRAVERSAL, 
QueryEngineSettings.OAK_QUERY_FAIL_TRAVERSAL);
         }
 
+        
queryEngineSettings.setIgnoredClassNamesInCallTrace(config.ignoredClassNamesInCallTrace());
+
         boolean fastQuerySizeSysProp = 
QueryEngineSettings.DEFAULT_FAST_QUERY_SIZE;
         boolean fastQuerySizeFromConfig = config.fastQuerySize();
         queryEngineSettings.setFastQuerySize(fastQuerySizeFromConfig || 
fastQuerySizeSysProp);
diff --git 
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUtilsTest.java
 
b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUtilsTest.java
index 32cea56..059aa64 100644
--- 
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUtilsTest.java
+++ 
b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexUtilsTest.java
@@ -28,6 +28,12 @@ import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE
 import static org.junit.Assert.*;
 
 public class IndexUtilsTest {
+    
+    // all relevant package TLDs
+    private static final String[] ALL_CLASSES_IGNORED = new String[] {"org", 
"com", "sun", "jdk", "java"};
+    
+    // all packages used with Oak
+    private static final String[] OAK_CLASSES_IGNORED = new String[] 
{"org.apache.jackrabbit", "java.lang", "sun.reflect", "jdk"};
 
     @Test
     public void asyncName() throws Exception {
@@ -41,4 +47,14 @@ public class IndexUtilsTest {
         assertEquals("async3", 
IndexUtils.getAsyncLaneName(builder.getNodeState(), "/fooIndex"));
     }
 
+    @Test
+    public void getCaller() {
+        assertNotNull(IndexUtils.getCaller(null));
+        assertNotNull(IndexUtils.getCaller(new String[0]));
+        
+        assertEquals("(internal)",IndexUtils.getCaller(ALL_CLASSES_IGNORED));
+        
+        String caller = IndexUtils.getCaller(OAK_CLASSES_IGNORED);
+        assertTrue(caller.startsWith("org.junit.runners"));
+    }  
 }
\ No newline at end of file
diff --git 
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexDeprecatedTest.java
 
b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexDeprecatedTest.java
index 3a773d2..45c1684 100644
--- 
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexDeprecatedTest.java
+++ 
b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexDeprecatedTest.java
@@ -106,7 +106,7 @@ public class PropertyIndexDeprecatedTest {
         propertyIndex.query(f, root);
         assertEquals("[[WARN] This index is deprecated: foo; " + 
                 "it is used for query Filter(query=" + 
-                "SELECT * FROM [nt:base], path=*, property=[foo=[x10]]). " + 
+                "SELECT * FROM [nt:base], path=*, property=[foo=[x10]]) called 
by (<function not configured>). " + 
                 "Please change the query or the index definitions.]", 
appender.list.toString());
         
         index = rootBuilder.child(INDEX_DEFINITIONS_NAME).child("foo");
diff --git 
a/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
 
b/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
index a1ee42d..a98248b 100644
--- 
a/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
+++ 
b/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
@@ -19,6 +19,7 @@
 package org.apache.jackrabbit.oak.spi.query;
 
 import org.apache.jackrabbit.oak.api.StrictPathRestriction;
+import org.jetbrains.annotations.NotNull;
 
 public interface QueryLimits {
 
@@ -33,5 +34,13 @@ public interface QueryLimits {
     default String getStrictPathRestriction() {
         return StrictPathRestriction.DISABLE.name();
     }
-
+    
+    /**
+     * Retrieve the java package names / full qualified class names which 
should be
+     * ignored when finding the class starting a query
+     * @return the name of the packages / full qualified class names
+     */
+    default @NotNull String[] getIgnoredClassNamesInCallTrace() {
+        return new String[] {};
+    }
 }
diff --git 
a/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
 
b/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
index ef85afb..9edb703 100644
--- 
a/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
+++ 
b/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
@@ -18,7 +18,7 @@
 /**
  * This package contains oak query index related classes.
  */
-@Version("1.4.0")
+@Version("1.5.0")
 package org.apache.jackrabbit.oak.spi.query;
 
 import org.osgi.annotation.versioning.Version;

Reply via email to