This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit fcc7a158dfcf7ed8e0e143c0d22b02417e97c3da Author: Andrus Adamchik <[email protected]> AuthorDate: Fri Jul 3 18:07:55 2026 -0400 CAY-2912 Compact SQL logger cleanup --- .../java/org/apache/cayenne/access/DataNode.java | 46 +++++++++------------- .../apache/cayenne/access/DataNodeQueryAction.java | 9 ++++- .../org/apache/cayenne/access/LoggingObserver.java | 20 +++------- .../apache/cayenne/access/OperationObserver.java | 6 +++ .../access/translator/TranslatedStatement.java | 5 +-- .../apache/cayenne/access/LoggingObserverTest.java | 10 ++--- .../org/apache/cayenne/access/MockDataNode.java | 6 +-- .../unit/telemetry/TelemetricDataNodeFactory.java | 4 +- 8 files changed, 48 insertions(+), 58 deletions(-) diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java index e0fc0a0e3..4839aa59b 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java @@ -222,22 +222,27 @@ public class DataNode { * * @since 1.1 */ - public void performQueries(Collection<? extends Query> queries, OperationObserver callback) { + public void performQueries(Collection<? extends Query> queries, OperationObserver operationObserver) { int listSize = queries.size(); if (listSize == 0) { return; } - if (callback.isIteratedResult() && listSize > 1) { + if (operationObserver.isIteratedResult() && listSize > 1) { throw new CayenneRuntimeException("Iterated queries are not allowed in a batch. Batch size: %d", listSize); } + // do this meaningless inexpensive operation to trigger AutoAdapter lazy initialization before opening a // connection. Otherwise, we may end up with two connections open simultaneously, possibly hitting connection // pool upper limit. getAdapter().getExtendedTypes(); + OperationObserver instrumentedObserver = sqlLogger.isEnabled() + ? new LoggingObserver(operationObserver, sqlLogger) + : operationObserver; + Transaction tx = BaseTransaction.getThreadTransaction(); Connection connection; @@ -248,32 +253,20 @@ public class DataNode { tx.setRollbackOnly(); } - callback.nextGlobalException(globalEx); + instrumentedObserver.nextGlobalException(globalEx); return; } - // when logging is enabled, wrap the observer so it can correlate each executed statement with its results - // and emit compact log lines; otherwise pass the caller's observer through untouched - SqlLogger logger = getSqlLogger(); - LoggingObserver loggingObserver = logger != null && logger.isEnabled() - ? new LoggingObserver(callback, logger) - : null; - OperationObserver observer = loggingObserver != null ? loggingObserver : callback; - - try { - DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, observer); + try { + DataNodeQueryAction queryRunner = new DataNodeQueryAction(this, instrumentedObserver); - boolean failed = false; for (Query nextQuery : queries) { // catch exceptions for each individual query try { queryRunner.runQuery(connection, nextQuery); } catch (Exception queryEx) { - // notify consumer of the exception, stop running further queries. The failing statement is not - // logged - its SQL and bindings travel with the thrown exception instead. - failed = true; - observer.nextQueryException(nextQuery, queryEx); + instrumentedObserver.nextQueryException(nextQuery, queryEx); if (tx != null) { tx.setRollbackOnly(); @@ -282,10 +275,7 @@ public class DataNode { } } - // flush any pending statement line (e.g. a summed batch) that completed successfully - if (!failed && loggingObserver != null) { - loggingObserver.flush(); - } + instrumentedObserver.afterLastStatement(); } finally { try { connection.close(); @@ -295,12 +285,12 @@ public class DataNode { } } - /** - * Returns EntityResolver that handles DataMaps of this node. - */ - public EntityResolver getEntityResolver() { - return entityResolver; - } + /** + * Returns EntityResolver that handles DataMaps of this node. + */ + public EntityResolver getEntityResolver() { + return entityResolver; + } /** * Sets EntityResolver. DataNode relies on externally set EntityResolver, so diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java b/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java index fe37e60f6..a952eb5ba 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/DataNodeQueryAction.java @@ -37,8 +37,8 @@ import java.util.List; */ class DataNodeQueryAction { - OperationObserver observer; - DataNode node; + final OperationObserver observer; + final DataNode node; public DataNodeQueryAction(DataNode node, OperationObserver observer) { this.observer = observer; @@ -56,6 +56,11 @@ class DataNodeQueryAction { observer.nextStatement(originalQuery, statement); } + @Override + public void afterLastStatement() { + observer.afterLastStatement(); + } + @Override public void nextBatchCount(Query query, int[] resultCount) { observer.nextBatchCount(originalQuery, resultCount); diff --git a/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java b/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java index 5e78ca5f5..e7435503a 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/LoggingObserver.java @@ -34,11 +34,6 @@ import java.util.List; * An {@link OperationObserver} decorator that correlates each executed statement (reported via * {@link #nextStatement}) with its results (reported via the {@code next*} callbacks) and drives a {@link SqlLogger} * to emit compact, single-line log messages. All callbacks are delegated to the wrapped observer unchanged. - * <p> - * The first result of a statement produces the main line (SQL + bindings + {@code selected:N}/{@code updated:N}); a - * statement that yields more results reports them as {@code also ...} lines — except batches, whose per-row update - * counts are summed into a single {@code updated:N} line. Exceptions are not logged (the SQL travels with the thrown - * exception instead). * * @since 5.0 */ @@ -57,15 +52,6 @@ class LoggingObserver implements OperationObserver { this.logger = logger; } - /** - * Emits any pending statement line (currently only summed batch updates) that has not been logged yet. Called by - * {@link DataNode} after the query loop completes. - */ - void flush() { - flushPending(); - current = null; - } - private void flushPending() { if (!headerEmitted && batchHasUpdate && current != null) { logger.logUpdate(current, batchUpdateSum); @@ -103,6 +89,12 @@ class LoggingObserver implements OperationObserver { return total; } + @Override + public void afterLastStatement() { + flushPending(); + current = null; + } + @Override public void nextStatement(Query query, TranslatedStatement statement) { flushPending(); diff --git a/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java b/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java index 8b56fecff..63a5a691f 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/OperationObserver.java @@ -42,6 +42,12 @@ public interface OperationObserver extends OperationHints { default void nextStatement(Query query, TranslatedStatement statement) { } + /** + * @since 5.0 + */ + default void afterLastStatement() { + } + /** * Callback method invoked after an updating query is executed. */ diff --git a/cayenne/src/main/java/org/apache/cayenne/access/translator/TranslatedStatement.java b/cayenne/src/main/java/org/apache/cayenne/access/translator/TranslatedStatement.java index e0492a3ba..6fd66d44b 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/translator/TranslatedStatement.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/translator/TranslatedStatement.java @@ -20,10 +20,7 @@ package org.apache.cayenne.access.translator; /** - * A common supertype for the immutable results of translating a query to SQL. It bundles the final SQL string with - * the typed, self-describing bindings needed to both execute and log a statement, and lets logging and error-reporting - * treat all four translation flavors ({@link TranslatedSelect}, {@link TranslatedBatch}, {@link TranslatedProcedure}, - * {@link TranslatedSQL}) uniformly. + * A common supertype for the immutable results of translating a query to SQL. * * @since 5.0 */ diff --git a/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java b/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java index 962213e05..ed62645c3 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/LoggingObserverTest.java @@ -117,7 +117,7 @@ public class LoggingObserverTest { observer.nextStatement(null, select()); observer.nextRows(null, asList(new Object(), new Object())); - observer.flush(); + observer.afterLastStatement(); assertEquals(List.of("selected:2"), logger.calls); } @@ -131,7 +131,7 @@ public class LoggingObserverTest { observer.nextCount(null, 1); observer.nextCount(null, 1); observer.nextCount(null, 1); - observer.flush(); + observer.afterLastStatement(); assertEquals(List.of("updated:3"), logger.calls); } @@ -145,7 +145,7 @@ public class LoggingObserverTest { observer.nextRows(null, List.of(new Object(), new Object(), new Object(), new Object(), new Object())); observer.nextCount(null, 10); observer.nextCount(null, 20); - observer.flush(); + observer.afterLastStatement(); assertEquals(List.of("selected:5", "also updated:10", "also updated:20"), logger.calls); } @@ -159,7 +159,7 @@ public class LoggingObserverTest { observer.nextStatement(null, select()); observer.nextRows(null, asList(new Object(), new Object())); observer.nextBatchCount(null, new int[0]); - observer.flush(); + observer.afterLastStatement(); assertEquals(List.of("selected:2"), logger.calls); } @@ -174,7 +174,7 @@ public class LoggingObserverTest { // a second batch statement should flush the first observer.nextStatement(null, batch()); observer.nextCount(null, 3); - observer.flush(); + observer.afterLastStatement(); assertEquals(List.of("updated:2", "updated:3"), logger.calls); } diff --git a/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java b/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java index 73f2b07e4..d669519fa 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/MockDataNode.java @@ -78,14 +78,14 @@ public class MockDataNode extends DataNode { } @Override - public void performQueries(Collection queries, OperationObserver resultConsumer) { + public void performQueries(Collection queries, OperationObserver operationObserver) { runCount += queries.size(); if (replaceResults) { - initWithPresetResults(queries, resultConsumer); + initWithPresetResults(queries, operationObserver); } else { - node.performQueries(queries, resultConsumer); + node.performQueries(queries, operationObserver); } } diff --git a/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java b/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java index 579ae7a2b..8a49337d1 100644 --- a/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java +++ b/cayenne/src/test/java/org/apache/cayenne/unit/telemetry/TelemetricDataNodeFactory.java @@ -44,11 +44,11 @@ public class TelemetricDataNodeFactory extends DefaultDataNodeFactory { } @Override - public void performQueries(Collection<? extends Query> queries, OperationObserver callback) { + public void performQueries(Collection<? extends Query> queries, OperationObserver operationObserver) { if (blockingQueries) { Assertions.fail("Query is unexpected: " + queries); } - super.performQueries(queries, callback); + super.performQueries(queries, operationObserver); queryCounter.addAndGet(queries.size()); }
