This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 805e3d603dbb21688fa7998c4e1a03e25dadd74c Author: opencode <[email protected]> AuthorDate: Thu Nov 5 15:33:36 2026 +0100 Document QueryStats sentinels and protect the composite schema Document the sentinels the direct QueryStats getters expose before an execution is booked, and that getPoolStats returns the live store. Return copies of the composite field name, description and type arrays so a caller cannot mutate the schema used to build the JMX CompositeType. Add a regression test for the copies. --- .../jdbc/pool/interceptor/SlowQueryReport.java | 33 ++++++++++++++-------- .../pool/interceptor/TestSlowQueryEviction.java | 18 ++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java index 1f3554b41f..50114a5573 100644 --- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java @@ -152,7 +152,8 @@ public class SlowQueryReport extends AbstractQueryReport { * * @return a hash map containing the statistics of the monitored queries, kept near {@code maxQueries} entries by * eviction, or {@code null} when no store is published under that name. A {@code null} name is answered - * the same way as a name that holds nothing, since nothing can be registered under it + * the same way as a name that holds nothing, since nothing can be registered under it. The map is the + * live store, not a copy: callers must not modify it */ public static ConcurrentHashMap<String, QueryStats> getPoolStats(String poolname) { if (poolname == null) { @@ -922,7 +923,7 @@ public class SlowQueryReport extends AbstractQueryReport { * @return the field names */ public static String[] getFieldNames() { - return FIELD_NAMES; + return FIELD_NAMES.clone(); } /** @@ -931,7 +932,7 @@ public class SlowQueryReport extends AbstractQueryReport { * @return the field descriptions */ public static String[] getFieldDescriptions() { - return FIELD_DESCRIPTIONS; + return FIELD_DESCRIPTIONS.clone(); } /** @@ -940,7 +941,7 @@ public class SlowQueryReport extends AbstractQueryReport { * @return the field types */ public static OpenType<?>[] getFieldTypes() { - return FIELD_TYPES; + return FIELD_TYPES.clone(); } @Override @@ -1114,36 +1115,44 @@ public class SlowQueryReport extends AbstractQueryReport { } /** - * Returns the longest time this query took to execute. + * Returns the longest time this query took to execute. Until an execution has been booked the value is + * {@link Long#MIN_VALUE}; the published views report {@code 0} in that state. * - * @return the maximum invocation time in milliseconds + * @return the maximum invocation time in milliseconds, or {@link Long#MIN_VALUE} while no execution has been + * booked */ public long getMaxInvocationTime() { return maxInvocationTime; } /** - * Returns the timestamp when the longest query execution occurred. + * Returns the timestamp when the longest query execution occurred. Until an execution has been booked the value + * is {@code 0}, because no date has been recorded. * - * @return the timestamp in milliseconds of the maximum invocation + * @return the timestamp in milliseconds of the maximum invocation, or {@code 0} while no execution has been + * booked */ public long getMaxInvocationDate() { return maxInvocationDate; } /** - * Returns the shortest time this query took to execute. + * Returns the shortest time this query took to execute. Until an execution has been booked the value is + * {@link Long#MAX_VALUE}; the published views report {@code 0} in that state. * - * @return the minimum invocation time in milliseconds + * @return the minimum invocation time in milliseconds, or {@link Long#MAX_VALUE} while no execution has been + * booked */ public long getMinInvocationTime() { return minInvocationTime; } /** - * Returns the timestamp when the shortest query execution occurred. + * Returns the timestamp when the shortest query execution occurred. Until an execution has been booked the value + * is {@code 0}, because no date has been recorded. * - * @return the timestamp in milliseconds of the minimum invocation + * @return the timestamp in milliseconds of the minimum invocation, or {@code 0} while no execution has been + * booked */ public long getMinInvocationDate() { return minInvocationDate; diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryEviction.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryEviction.java index fc2503097c..c394650608 100644 --- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryEviction.java +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestSlowQueryEviction.java @@ -318,4 +318,22 @@ class TestSlowQueryEviction extends JdbcPoolBaseTest { Assertions.assertEquals(42L, ((Number) data.get("minInvocationTime")).longValue(), "the first execution must publish the booked time"); } + + @Test + void theCompositeSchemaAccessorsReturnCopies() { + String[] names = SlowQueryReport.QueryStats.getFieldNames(); + names[0] = "mutated"; + Assertions.assertNotEquals("mutated", SlowQueryReport.QueryStats.getFieldNames()[0], + "mutating the returned field names must not change the JMX schema"); + + String[] descriptions = SlowQueryReport.QueryStats.getFieldDescriptions(); + descriptions[0] = "mutated"; + Assertions.assertNotEquals("mutated", SlowQueryReport.QueryStats.getFieldDescriptions()[0], + "mutating the returned field descriptions must not change the JMX schema"); + + javax.management.openmbean.OpenType<?>[] types = SlowQueryReport.QueryStats.getFieldTypes(); + types[0] = null; + Assertions.assertNotNull(SlowQueryReport.QueryStats.getFieldTypes()[0], + "mutating the returned field types must not change the JMX schema"); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
