Author: thomasm
Date: Fri May 17 14:28:38 2019
New Revision: 1859436

URL: http://svn.apache.org/viewvc?rev=1859436&view=rev
Log:
OAK-8309 SLOW_QUERY_COUNT don't get updated for each slow query

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/RuntimeNodeTraversalException.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/SlowQueryMetricTest.java
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/FilterIterators.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/stats/QueryStatsData.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReopenedLuceneIndexTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/FilterIterators.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/FilterIterators.java?rev=1859436&r1=1859435&r2=1859436&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/FilterIterators.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/FilterIterators.java
 Fri May 17 14:28:38 2019
@@ -48,7 +48,7 @@ public class FilterIterators {
             String message = "The query read more than " + 
                     maxMemoryEntries + " nodes in memory.";
             UnsupportedOperationException e = new 
UnsupportedOperationException(
-                    message + 
+                    message +
                     " To avoid running out of memory, processing was 
stopped.");
             LOG.warn(message, e);
             throw e;
@@ -60,14 +60,14 @@ public class FilterIterators {
      * 
      * @param count the number of read operations
      * @param settings the query engine settings
-     * @throws UnsupportedOperationException if the limit was exceeded
+     * @throws RuntimeNodeTraversalException if the limit was exceeded
      */
     public static void checkReadLimit(long count, QueryLimits settings) {
         long maxReadEntries = settings.getLimitReads();
         if (count > maxReadEntries) {
             String message = "The query read or traversed more than " + 
                     maxReadEntries + " nodes.";
-            UnsupportedOperationException e = new 
UnsupportedOperationException(
+            RuntimeNodeTraversalException e = new 
RuntimeNodeTraversalException(
                     message + 
                     " To avoid affecting other tasks, processing was 
stopped.");
             LOG.warn(message, e);

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/RuntimeNodeTraversalException.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/RuntimeNodeTraversalException.java?rev=1859436&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/RuntimeNodeTraversalException.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/RuntimeNodeTraversalException.java
 Fri May 17 14:28:38 2019
@@ -0,0 +1,27 @@
+/*
+ * 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.query;
+
+/**
+ * The exception thrown when traversing too many entries in the result.
+ */
+public class RuntimeNodeTraversalException extends 
UnsupportedOperationException {
+
+    public RuntimeNodeTraversalException(String message) {
+        super(message);
+    }
+}

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1859436&r1=1859435&r2=1859436&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
 Fri May 17 14:28:38 2019
@@ -38,8 +38,10 @@ import org.apache.jackrabbit.oak.core.Im
 import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
 import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
 import org.apache.jackrabbit.oak.query.ExecutionContext;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.query.QueryOptions;
+import org.apache.jackrabbit.oak.query.RuntimeNodeTraversalException;
 import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.query.plan.ExecutionPlan;
@@ -56,6 +58,8 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.stats.StatsOptions;
 import org.apache.jackrabbit.oak.stats.TimerStats;
+import org.apache.jackrabbit.oak.stats.CounterStats;
+import org.apache.jackrabbit.oak.stats.HistogramStats;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -75,6 +79,11 @@ public class SelectorImpl extends Source
     // The sample rate. Must be a power of 2.
     private static final Long TIMER_SAMPLE_RATE = 
Long.getLong("oak.query.timerSampleRate", 0x100);
     
+    private static final long SLOW_QUERY_HISTOGRAM = 1;
+    private static final long TOTAL_QUERY_HISTOGRAM = 0;
+    private static final String SLOW_QUERY_PERCENTILE_METRICS_NAME = 
"SLOW_QUERY_PERCENTILE_METRICS";
+    private static final String SLOW_QUERY_COUNT_NAME = "SLOW_QUERY_COUNT";
+
     private static long timerSampleCounter;
     
     // TODO possibly support using multiple indexes (using index intersection 
/ index merge)
@@ -171,6 +180,8 @@ public class SelectorImpl extends Source
 
     private CachedTree cachedTree;
 
+    private boolean updateTotalQueryHistogram = true;
+
     public SelectorImpl(NodeTypeInfo nodeTypeInfo, String selectorName) {
         this.nodeTypeInfo = checkNotNull(nodeTypeInfo);
         this.selectorName = checkNotNull(selectorName);
@@ -503,8 +514,15 @@ public class SelectorImpl extends Source
     private boolean nextInternal() {
         while (cursor != null && cursor.hasNext()) {
             scanCount++;
-            query.getQueryExecutionStats().scan(1, scanCount, 
query.getSettings());
-            currentRow = cursor.next();
+            query.getQueryExecutionStats().scan(1, scanCount);
+            try {
+                totalQueryStats(query.getSettings());
+                currentRow = cursor.next();
+            } catch (RuntimeNodeTraversalException e) {
+                addSlowQueryStats(query.getSettings());
+                LOG.warn(e.getMessage() + " for query " + 
query.getStatement());
+                throw e;
+            }
             if (isParent) {
                 // we must not check whether the _parent_ is readable
                 // for joins of type
@@ -541,6 +559,21 @@ public class SelectorImpl extends Source
         return false;
     }
 
+    private void totalQueryStats(QueryEngineSettings queryEngineSettings) {
+        if (updateTotalQueryHistogram) {
+            updateTotalQueryHistogram = false;
+            HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
+            histogramStats.update(TOTAL_QUERY_HISTOGRAM);
+        }
+    }
+
+    private void addSlowQueryStats(QueryEngineSettings queryEngineSettings) {
+        HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
+        histogramStats.update(SLOW_QUERY_HISTOGRAM);
+        CounterStats slowQueryCounter = 
queryEngineSettings.getStatisticsProvider().getCounterStats(SLOW_QUERY_COUNT_NAME,
 StatsOptions.METRICS_ONLY);
+        slowQueryCounter.inc();
+    }
+
     private boolean evaluateCurrentRow() {
         if (currentRow.isVirtualRow()) {
             //null path implies that all checks are already done -- we just 
need to pass it through

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/stats/QueryStatsData.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/stats/QueryStatsData.java?rev=1859436&r1=1859435&r2=1859436&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/stats/QueryStatsData.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/stats/QueryStatsData.java
 Fri May 17 14:28:38 2019
@@ -17,10 +17,6 @@
 package org.apache.jackrabbit.oak.query.stats;
 
 import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
-import org.apache.jackrabbit.oak.query.QueryEngineSettings;
-import org.apache.jackrabbit.oak.stats.CounterStats;
-import org.apache.jackrabbit.oak.stats.HistogramStats;
-import org.apache.jackrabbit.oak.stats.StatsOptions;
 
 public class QueryStatsData {
     
@@ -47,8 +43,6 @@ public class QueryStatsData {
     private long readNanos;
     private long maxTimeNanos;
     private boolean captureStackTraces;
-    private boolean isSlowQuery = false;
-    private boolean updateTotalQueryHistogram = true;
 
     public QueryStatsData(String query, String language) {
         this.query = query;
@@ -183,22 +177,9 @@ public class QueryStatsData {
             maxTimeNanos = Math.max(maxTimeNanos, time);
         }
 
-        public void scan(long count, long max, QueryEngineSettings 
queryEngineSettings) {
+        public void scan(long count, long max) {
             totalRowsScanned += count;
             maxRowsScanned = Math.max(maxRowsScanned, max);
-            long maxScannedLimit = Math.min(SLOW_QUERY_LIMIT_SCANNED, 
queryEngineSettings.getLimitReads());
-            if (updateTotalQueryHistogram) {
-                updateTotalQueryHistogram = false;
-                HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
-                histogramStats.update(TOTAL_QUERY_HISTOGRAM);
-            }
-            if (totalRowsScanned >= maxScannedLimit && !isSlowQuery) {
-                isSlowQuery = true;
-                HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
-                histogramStats.update(SLOW_QUERY_HISTOGRAM);
-                CounterStats slowQueryCounter = 
queryEngineSettings.getStatisticsProvider().getCounterStats(SLOW_QUERY_COUNT_NAME,
 StatsOptions.METRICS_ONLY);
-                slowQueryCounter.inc();
-            }
         }
     }
 

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/SlowQueryMetricTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/SlowQueryMetricTest.java?rev=1859436&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/SlowQueryMetricTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/query/SlowQueryMetricTest.java
 Fri May 17 14:28:38 2019
@@ -0,0 +1,142 @@
+/*
+ * 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.spi.query;
+
+import org.apache.jackrabbit.oak.InitialContent;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.QueryEngine;
+import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.ResultRow;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.apache.jackrabbit.oak.plugins.metric.MetricStatisticsProvider;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.RuntimeNodeTraversalException;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.stats.CounterStats;
+import org.apache.jackrabbit.oak.stats.HistogramStats;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.jackrabbit.oak.stats.StatsOptions;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.query.Query;
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * {@code SlowQueryMetricTest} contains slowQuery metrics related tests.
+ */
+public class SlowQueryMetricTest {
+
+    private ContentRepository repository;
+    private ScheduledExecutorService executor = 
Executors.newSingleThreadScheduledExecutor();
+    private MetricStatisticsProvider statsProvider =
+            new 
MetricStatisticsProvider(ManagementFactory.getPlatformMBeanServer(), executor);
+    private QueryEngineSettings queryEngineSettings = new 
QueryEngineSettings(statsProvider);
+
+
+    Oak oak = null;
+
+    @Before
+    public void setUp() {
+        queryEngineSettings.setLimitReads(11);
+        Whiteboard whiteboard = new DefaultWhiteboard();
+        whiteboard.register(StatisticsProvider.class, statsProvider, 
Collections.emptyMap());
+        oak = new Oak().with(new OpenSecurityProvider()).with(new 
InitialContent()).with(queryEngineSettings).with(whiteboard);
+        repository = oak.createContentRepository();
+    }
+
+    @After
+    public void tearDown() {
+        repository = null;
+        statsProvider.close();
+        new ExecutorCloser(executor).close();
+    }
+
+    private String SLOW_QUERY_COUNT_NAME = "SLOW_QUERY_COUNT";
+    private String SLOW_QUERY_PERCENTILE_METRICS_NAME = 
"SLOW_QUERY_PERCENTILE_METRICS";
+
+    @Test
+    public void queryOnStableRevision() throws Exception {
+        long maxReadEntries = 1000;//we check for max traversals for each 1000 
node reads, see Cursors.java -> fetchNext()
+        ContentSession s = repository.login(null, null);
+        Root r = s.getLatestRoot();
+        Tree t = r.getTree("/").addChild("test");
+        for (int i = 0; i < maxReadEntries + 1; i++) {
+            t.addChild("node" + i).setProperty("jcr:primaryType", "nt:base");
+        }
+        r.commit();
+        ContentSession s2 = repository.login(null, null);
+        Root r2 = s2.getLatestRoot();
+        CounterStats slowQueryCounter = 
queryEngineSettings.getStatisticsProvider().getCounterStats(SLOW_QUERY_COUNT_NAME,
 StatsOptions.METRICS_ONLY);
+        HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
+        long totalQueryCount = histogramStats.getCount();
+        long slowQueryCount = slowQueryCounter.getCount();
+        Assert.assertEquals(totalQueryCount, 0);
+        Assert.assertEquals(slowQueryCount, 0);
+
+        Result result = executeQuery(r2, "test/node1//element(*, nt:base)");
+        for (ResultRow rr : result.getRows()) {
+        }
+        totalQueryCount = histogramStats.getCount();
+        slowQueryCount = slowQueryCounter.getCount();
+        Assert.assertEquals(totalQueryCount, 1);
+        Assert.assertEquals(slowQueryCount, 0);
+
+        executeAndAssertSlowQuery(r2, queryEngineSettings);
+    }
+
+    private void executeAndAssertSlowQuery(Root r2, QueryEngineSettings 
queryEngineSettings) throws ParseException {
+        Result result = executeQuery(r2, "test//element(*, nt:base)");
+        CounterStats slowQueryCounter = 
queryEngineSettings.getStatisticsProvider().getCounterStats(SLOW_QUERY_COUNT_NAME,
 StatsOptions.METRICS_ONLY);
+        HistogramStats histogramStats = 
queryEngineSettings.getStatisticsProvider().getHistogram(SLOW_QUERY_PERCENTILE_METRICS_NAME,
 StatsOptions.METRICS_ONLY);
+        long initialSlowQueryCounter = slowQueryCounter.getCount();
+        long initialHistogramCounter = histogramStats.getCount();
+        try {
+            for (ResultRow rr : result.getRows()) {
+            }
+        } catch (RuntimeNodeTraversalException e) {
+
+            /*
+             count increased by 2. one for being a query and one for being 
slow query. Added twice to get histogram percentile info
+             */
+            Assert.assertEquals(histogramStats.getCount(), 
initialHistogramCounter + 2);
+            Assert.assertEquals(slowQueryCounter.getCount(), 
initialSlowQueryCounter + 1);
+            return;
+        }
+        Assert.fail("Unable to catch max Node Traversal limit breach");
+    }
+
+    private Result executeQuery(Root r2, String queryString) throws 
ParseException {
+        Result result = r2.getQueryEngine().executeQuery(queryString, 
Query.XPATH,
+                QueryEngine.NO_BINDINGS, QueryEngine.NO_MAPPINGS);
+        return result;
+    }
+}

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReopenedLuceneIndexTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReopenedLuceneIndexTest.java?rev=1859436&r1=1859435&r2=1859436&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReopenedLuceneIndexTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReopenedLuceneIndexTest.java
 Fri May 17 14:28:38 2019
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
 import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.RuntimeNodeTraversalException;
 import org.apache.jackrabbit.oak.spi.commit.Observer;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
@@ -135,7 +136,7 @@ public class ReopenedLuceneIndexTest {
 
     @Test
     public void resultSizeAboveLimitCompatV1() throws Exception {
-        thrown.expect(UnsupportedOperationException.class);
+        thrown.expect(RuntimeNodeTraversalException.class);
         thrown.expectMessage(StringContains.containsString("The query read or 
traversed more than " + READ_LIMIT + " nodes. To avoid affecting other tasks, 
processing was stopped."));
 
         // Add more data such that the query genuinely supasses query limit
@@ -146,7 +147,7 @@ public class ReopenedLuceneIndexTest {
 
     @Test
     public void resultSizeAboveLimitCompatV2() throws Exception {
-        thrown.expect(UnsupportedOperationException.class);
+        thrown.expect(RuntimeNodeTraversalException.class);
         thrown.expectMessage(StringContains.containsString("The query read or 
traversed more than " + READ_LIMIT + " nodes. To avoid affecting other tasks, 
processing was stopped."));
 
         // Add more data such that the query genuinely supasses query limit


Reply via email to