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 jo...@apache.org on 2025/07/14 08:01:52 UTC
(jackrabbit-oak) 01/01: OAK-11672 log warnings when fetching large result sets
This is an automated email from the ASF dual-hosted git repository.
joerghoh pushed a commit to branch OAK-11672-query-resultset
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 6d33cf4b75b76696016668b8a099dd5805b93a29
Author: Joerg Hoh <jh...@adobe.com>
AuthorDate: Mon Jul 14 10:01:38 2025 +0200
OAK-11672 log warnings when fetching large result sets
---
.../jackrabbit/oak/jcr/query/QueryManagerImpl.java | 2 +-
.../oak/jcr/query/QueryResultDebugIterator.java | 83 ++++++++++++++++++++++
.../jackrabbit/oak/jcr/query/QueryResultImpl.java | 15 +++-
3 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java
index b169e3ebdb..afd8744367 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryManagerImpl.java
@@ -142,7 +142,7 @@ public class QueryManagerImpl implements QueryManager {
queryOpsLogger.debug("Executed query [{}] in [{}] ms", statement, millis);
sessionContext.getStatisticManager()
.logQueryEvaluationTime(language, statement, millis);
- return new QueryResultImpl(sessionContext, r);
+ return new QueryResultImpl(sessionContext, r, statement, language);
} catch (IllegalArgumentException e) {
throw new InvalidQueryException(e);
} catch (ParseException e) {
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultDebugIterator.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultDebugIterator.java
new file mode 100644
index 0000000000..ac0505cdd4
--- /dev/null
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultDebugIterator.java
@@ -0,0 +1,83 @@
+/*
+ * 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.jcr.query;
+
+import java.util.Iterator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An iterator which prints warnings when a certain number of elements were read from it.
+ * @param <K>
+ */
+
+public class QueryResultDebugIterator<K> implements Iterator<K> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(QueryResultDebugIterator.class);
+
+ private Iterator<K> iter;
+ private int count;
+ private String query;
+ private String queryLanguage;
+
+ private static final int FIRST_LOG_THRESHOLD = 1_000;
+ private static final int SECOND_LOG_THRESHOLD = 10_000;
+
+
+ public QueryResultDebugIterator (Iterator<K> it, String query, String queryLanguage) {
+ this.iter = it;
+ this.query = query;
+ this.queryLanguage = queryLanguage;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ @Override
+ public K next() {
+ mark();
+ if (count >= FIRST_LOG_THRESHOLD) {
+ potentiallyLog();
+ }
+ return iter.next();
+ }
+
+ protected void mark() {
+ count++;
+ }
+
+ private void potentiallyLog() {
+ if (count == FIRST_LOG_THRESHOLD) {
+ LOG.warn("Read {} results from result set of query='{}', query language='{}')", count, query, queryLanguage);
+ return;
+ }
+ if (count == SECOND_LOG_THRESHOLD) {
+ LOG.warn("Read {} results from result set of query='{}', query language='{}')", count, query, queryLanguage);
+ return;
+ }
+ if (count > SECOND_LOG_THRESHOLD && count % 1000 == 0) {
+ LOG.trace("Read {} results from result set of query='{}', query language='{}')", count, query, queryLanguage);
+ }
+ }
+
+
+}
diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
index 3d5de8380e..0ece0831c2 100644
--- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
+++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
@@ -61,11 +61,16 @@ public class QueryResultImpl implements QueryResult {
private final PartialValueFactory valueFactory;
- public QueryResultImpl(SessionContext sessionContext, Result result) {
+ private final String queryStatement;
+ private final String queryLanguage;
+
+ public QueryResultImpl(SessionContext sessionContext, Result result, String query, String queryLanguage) {
this.sessionContext = sessionContext;
this.sessionDelegate = sessionContext.getSessionDelegate();
this.result = result;
this.valueFactory = new PartialValueFactory(sessionContext, sessionContext.getBlobAccessProvider());
+ this.queryStatement = query;
+ this.queryLanguage = queryLanguage;
}
@Override
@@ -231,10 +236,14 @@ public class QueryResultImpl implements QueryResult {
fastSizeCallback = result;
}
});
- return new NodeIteratorAdapter(prefIt) {
+ final QueryResultDebugIterator<NodeImpl<? extends NodeDelegate>> debugIt =
+ new QueryResultDebugIterator<>(prefIt, queryStatement, queryLanguage);
+
+ return new NodeIteratorAdapter(debugIt) {
@Override
public long getSize() {
- return prefIt.size();
+ return prefIt.size(); // bypass the debugIterator, as it does not influence
+ // the result set
}
};
}