From fc3dc0234c5cd9a4bb39848c20224cff8661a68c Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Mon, 25 Nov 2024 16:22:06 +0100 Subject: [PATCH 1/4] OF-2913: Fix db statistics The end-time of a profiling session is now observed when calculating rates. Prior to this change, no new data was recorded, but the end-time that was used was 'now', leading to decreasing rates over time. When (re)starting a profiling session, all old data should be discarded, to avoid skewed averages and rates. --- .../database/ProfiledConnection.java | 44 ++- .../database/ProfiledConnectionTest.java | 279 ++++++++++++++++++ 2 files changed, 296 insertions(+), 27 deletions(-) create mode 100644 xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java diff --git a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java index bd4890b2b2..11c9c81d2b 100644 --- a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java +++ b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Jive Software, 2017-2023 Ignite Realtime Foundation. All rights reserved. + * Copyright (C) 2004 Jive Software, 2017-2024 Ignite Realtime Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,15 +60,8 @@ public static enum Type { } - private static long startInsertTime = 0; - private static long startUpdateTime = 0; - private static long startSelectTime = 0; - private static long startDeleteTime = 0; - - private static long endInsertTime = 0; - private static long endUpdateTime = 0; - private static long endSelectTime = 0; - private static long endDeleteTime = 0; + private static long startTime = 0; + private static long endTime = 0; private static long insertCount = 0; private static long updateCount = 0; @@ -93,15 +86,16 @@ public static enum Type { * Start profiling. */ public static void start() { - long now = System.currentTimeMillis(); - startInsertTime = startUpdateTime = startSelectTime = startDeleteTime = now; + resetStatistics(); + startTime = System.currentTimeMillis(); + endTime = 0; } /** * Stop profiling. */ public static void stop() { - endInsertTime = endUpdateTime = endSelectTime = endDeleteTime = 0; + endTime = System.currentTimeMillis(); } /** @@ -140,6 +134,10 @@ public static void addQuery(Type type, String sql, long time) { return; } + if (startTime == 0 || endTime > startTime) { + return; + } + // clean up sql to insert spaces after every ',' sql = reformatQuery(sql); @@ -203,28 +201,20 @@ public static void addQuery(Type type, String sql, long time) { * second. */ public static double getQueriesPerSecond(Type type) { - long count, start, end; + long count; switch (type) { case select: count = selectCount; - start = startSelectTime; - end = endSelectTime; break; case update: count = updateCount; - start = startUpdateTime; - end = endUpdateTime; break; case insert: count = insertCount; - start = startInsertTime; - end = endInsertTime; break; case delete: count = deleteCount; - start = startDeleteTime; - end = endDeleteTime; break; default: throw new IllegalArgumentException("Invalid type"); @@ -235,11 +225,11 @@ public static double getQueriesPerSecond(Type type) { } // If the profiling hasn't been stopped yet, we want to give // profiling values up to the current time instead. - if (end == 0) { - end = System.currentTimeMillis(); + if (endTime == 0) { + endTime = System.currentTimeMillis(); } // Compute the number of seconds - double time = (end - start) / 1000.0; + double time = (endTime - startTime) / 1000.0; // Finally, return the average. return count / time; } @@ -353,8 +343,8 @@ public static ProfiledConnectionEntry[] getSortedQueries(Type type, boolean sort * Reset all statistics. */ public static void resetStatistics() { - startInsertTime = startUpdateTime = startSelectTime = startDeleteTime = 0; - endInsertTime = endUpdateTime = endSelectTime = endDeleteTime = 0; + startTime = 0; + endTime = 0; insertCount = updateCount = selectCount = deleteCount = 0; totalInsertTime = totalUpdateTime = totalSelectTime = totalDeleteTime = 0; diff --git a/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java b/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java new file mode 100644 index 0000000000..1ae1f70656 --- /dev/null +++ b/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2024 Ignite Realtime Foundation. All rights reserved. + * + * Licensed 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.jivesoftware.database; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests that verify the functionality of {@link ProfiledConnection} + * + * @author Guus der Kinderen, guus.der.kinderen@gmail.com + */ +public class ProfiledConnectionTest +{ + @BeforeEach + public void resetStatistics() { + ProfiledConnection.resetStatistics(); + } + + @AfterEach + public void stopCollecting() { + ProfiledConnection.stop(); + ProfiledConnection.resetStatistics(); + } + + @Test + public void testAverageQueryTime() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); + final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(5, result); + } + + @Test + public void testQueriesPerSecondNotStarted() throws Exception + { + // Setup test fixture. + ProfiledConnection.stop(); + + // Execute system under test. + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testQueriesPerSecondNoQueries() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testQueriesPerSecondStartedNotStopped() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertTrue(result > 0); + } + + @Test + public void testQueriesPerSecondStartedAndStopped() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertTrue(result > 0); + } + + @Test + public void testAverageQueryTimeCollectedWhenProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(2, result); + } + + @Test + public void testAverageQueryTimeNotCollectedWhenNotProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.stop(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testQueriesPerSecondCollectedWhenProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertNotEquals(0, result); + } + + @Test + public void testQueriesPerSecondNotCollectedWhenNotProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.stop(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testQueryCountCollectedWhenProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(1, result); + } + + @Test + public void testQueryCountNotCollectedWhenNotProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.stop(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testTotalQueryTimeCollectedWhenProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(2, result); + } + + @Test + public void testTotalQueryTimeNotCollectedWhenNotProfiling() throws Exception + { + // Setup test fixture. + ProfiledConnection.stop(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(0, result); + } + + @Test + public void testStatsDontResetAtStop() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + ProfiledConnection.stop(); + + // Execute system under test. + final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(2, result); + } + + @Test + public void testStartResetsStatistics() + { + // Setup test fixture. + ProfiledConnection.start(); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + ProfiledConnection.stop(); + ProfiledConnection.start(); + + // Execute system under test. + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); + + // Verify results. + assertEquals(1, result); + } + + @Test + public void testQueriesPerSecondCalculatedBasedOnEndTime() throws Exception + { + // Setup test fixture. + ProfiledConnection.start(); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + Thread.sleep(5); // To prevent 'infinity' + final double expected = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + ProfiledConnection.stop(); + + // Execute system under test. + Thread.sleep(50); + final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); + + // Verify results. + assertTrue(result > expected*.25, "Expected value '" + result + "' to be roughly equal to '" + expected + "', but it was significantly different."); // result will typically be _exact_, but the execution time of getQueriesPerSecond() and stop() may introduce a bit of drift. + assertTrue(result < expected*2, "Expected value '" + result + "' to be roughly equal to '" + expected + "', but it was significantly different."); // result will typically be _exact_, but the execution time of getQueriesPerSecond() and stop() may introduce a bit of drift. + } +} From e3abd089d78ec83dc354b12c4186cf5870330df1 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Mon, 25 Nov 2024 16:33:50 +0100 Subject: [PATCH 2/4] Apply IDE hints to ProfiledConnection.java Multiple small, non-functional changes have been applied to the code of ProfiledConnection. This class now requires Java 17. --- .../database/ProfiledConnection.java | 210 ++++-------------- 1 file changed, 41 insertions(+), 169 deletions(-) diff --git a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java index 11c9c81d2b..49d17eb959 100644 --- a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java +++ b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java @@ -36,7 +36,7 @@ public class ProfiledConnection extends AbstractConnection { private static final Logger Log = LoggerFactory.getLogger(ProfiledConnection.class); - public static enum Type { + public enum Type { /** * Constant for SELECT database queries. @@ -73,14 +73,10 @@ public static enum Type { private static long totalSelectTime = 0; private static long totalDeleteTime = 0; - private static Map insertQueries = - new Hashtable(); - private static Map updateQueries = - new Hashtable(); - private static Map selectQueries = - new Hashtable(); - private static Map deleteQueries = - new Hashtable(); + private static final Map insertQueries = new Hashtable<>(); + private static final Map updateQueries = new Hashtable<>(); + private static final Map selectQueries = new Hashtable<>(); + private static final Map deleteQueries = new Hashtable<>(); /** * Start profiling. @@ -107,18 +103,12 @@ public static void stop() { * @return the number queries of type {@code type} performed. */ public static long getQueryCount(Type type) { - switch (type) { - case select: - return selectCount; - case update: - return updateCount; - case insert: - return insertCount; - case delete: - return deleteCount; - default: - throw new IllegalArgumentException("Invalid type"); - } + return switch (type) { + case select -> selectCount; + case update -> updateCount; + case insert -> insertCount; + case delete -> deleteCount; + }; } /** @@ -130,7 +120,7 @@ public static long getQueryCount(Type type) { */ public static void addQuery(Type type, String sql, long time) { // Do nothing if we didn't receive a sql statement - if (sql == null || sql.equals("")) { + if (sql == null || sql.isEmpty()) { return; } @@ -201,24 +191,13 @@ public static void addQuery(Type type, String sql, long time) { * second. */ public static double getQueriesPerSecond(Type type) { - long count; + long count = switch (type) { + case select -> selectCount; + case update -> updateCount; + case insert -> insertCount; + case delete -> deleteCount; + }; - switch (type) { - case select: - count = selectCount; - break; - case update: - count = updateCount; - break; - case insert: - count = insertCount; - break; - case delete: - count = deleteCount; - break; - default: - throw new IllegalArgumentException("Invalid type"); - } // if no queries yet, return 0; if (count == 0) { return 0; @@ -284,18 +263,12 @@ public static double getAverageQueryTime(Type type) { * query. */ public static long getTotalQueryTime(Type type) { - switch (type) { - case select: - return totalSelectTime; - case update: - return totalUpdateTime; - case insert: - return totalInsertTime; - case delete: - return totalDeleteTime; - default: - throw new IllegalArgumentException("Invalid type"); - } + return switch (type) { + case select -> totalSelectTime; + case update -> totalUpdateTime; + case insert -> totalInsertTime; + case delete -> totalDeleteTime; + }; } /** @@ -307,32 +280,19 @@ public static long getTotalQueryTime(Type type) { * @return an array of ProfiledConnectionEntry objects */ public static ProfiledConnectionEntry[] getSortedQueries(Type type, boolean sortByTime) { - Map queries; - - switch (type) { - case select: - queries = selectQueries; - break; - case update: - queries = updateQueries; - break; - case insert: - queries = insertQueries; - break; - case delete: - queries = deleteQueries; - break; - default: - throw new IllegalArgumentException("Invalid type"); - } + Map queries = switch (type) { + case select -> selectQueries; + case update -> updateQueries; + case insert -> insertQueries; + case delete -> deleteQueries; + }; // No queries, return null if (queries.isEmpty()) { return null; } - ProfiledConnectionEntry [] result = queries.values().toArray( - new ProfiledConnectionEntry[queries.size()]); + ProfiledConnectionEntry[] result = queries.values().toArray(new ProfiledConnectionEntry[0]); quickSort(result, sortByTime, 0, result.length - 1); return result; @@ -392,7 +352,7 @@ private static void swap(Object[] list, int i, int j) { private static String removeQueryValues(String _sql) { int length = _sql.length(); - if (_sql.indexOf("=") == -1) { + if (!_sql.contains("=")) { return _sql; } @@ -440,7 +400,7 @@ else if (afterEquals && inValue && hasQuotes) { } break; } - case '-': + case '-', '9', '8', '7', '6', '5', '4', '3', '2', '1', '0', '+': { if (afterEquals && !inValue) { startValue = x; @@ -449,94 +409,6 @@ else if (afterEquals && inValue && hasQuotes) { } break; } - case '+': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '0': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '1': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '2': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '3': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '4': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '5': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '6': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '7': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '8': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } - case '9': - { - if (afterEquals && !inValue) { - startValue = x; - inValue = true; - } - break; - } default: { if (afterEquals && !inValue) { @@ -648,9 +520,9 @@ public CallableStatement prepareCall(String sql, int i, int i1) throws SQLExcept * Statement object and performs timings of the database queries. The class * does not handle batch queries but should generally work otherwise. */ - class TimedStatement extends StatementWrapper { + static class TimedStatement extends StatementWrapper { - private Statement stmt; + private final Statement stmt; /** * Creates a new TimedStatement that wraps {@code stmt}. @@ -738,10 +610,10 @@ else if (sqlL.startsWith("delete")) { * underlying PreparedStatement object and performs timings of the database * queries. */ - class TimedPreparedStatement extends PreparedStatementWrapper { + static class TimedPreparedStatement extends PreparedStatementWrapper { - private String sql; - private Type type = Type.select; + private final String sql; + private final Type type; public TimedPreparedStatement(PreparedStatement pstmt, String sql) { super(pstmt); @@ -943,10 +815,10 @@ else if (sqlL.startsWith("delete")) { * underlying CallableStatement object and performs timings of the database * queries. */ - class TimedCallableStatement extends CallableStatementWrapper { + static class TimedCallableStatement extends CallableStatementWrapper { - private String sql; - private Type type = Type.select; + private final String sql; + private final Type type; public TimedCallableStatement(CallableStatement cstmt, String sql) { super(cstmt); From dd208d413f56e9ccc6c775356690f2157f7d2c50 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Mon, 25 Nov 2024 17:56:13 +0100 Subject: [PATCH 3/4] Use java.time when collecting database statistics Use the more type-safe Instant and Duration representations from `java.time` (rather than long values representing a timestamp and durations) in the code that profiles database statistics --- .../database/ProfiledConnection.java | 302 +++++++++--------- .../database/ProfiledConnectionEntry.java | 8 +- .../src/main/webapp/server-db-stats.jsp | 32 +- .../database/ProfiledConnectionTest.java | 65 ++-- 4 files changed, 212 insertions(+), 195 deletions(-) diff --git a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java index 49d17eb959..be0de89f29 100644 --- a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java +++ b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnection.java @@ -20,6 +20,8 @@ import org.slf4j.LoggerFactory; import java.sql.*; +import java.time.Duration; +import java.time.Instant; import java.util.*; /** @@ -60,18 +62,18 @@ public enum Type { } - private static long startTime = 0; - private static long endTime = 0; + private static Instant startTime = null; + private static Instant endTime = null; private static long insertCount = 0; private static long updateCount = 0; private static long selectCount = 0; private static long deleteCount = 0; - private static long totalInsertTime = 0; - private static long totalUpdateTime = 0; - private static long totalSelectTime = 0; - private static long totalDeleteTime = 0; + private static Duration totalInsertTime = Duration.ZERO; + private static Duration totalUpdateTime = Duration.ZERO; + private static Duration totalSelectTime = Duration.ZERO; + private static Duration totalDeleteTime = Duration.ZERO; private static final Map insertQueries = new Hashtable<>(); private static final Map updateQueries = new Hashtable<>(); @@ -83,15 +85,15 @@ public enum Type { */ public static void start() { resetStatistics(); - startTime = System.currentTimeMillis(); - endTime = 0; + startTime = Instant.now(); + endTime = null; } /** * Stop profiling. */ public static void stop() { - endTime = System.currentTimeMillis(); + endTime = Instant.now(); } /** @@ -118,13 +120,14 @@ public static long getQueryCount(Type type) { * @param sql the insert sql string. * @param time the length of time the query took in milliseconds */ - public static void addQuery(Type type, String sql, long time) { + public static void addQuery(Type type, String sql, Duration time) { // Do nothing if we didn't receive a sql statement if (sql == null || sql.isEmpty()) { return; } - if (startTime == 0 || endTime > startTime) { + // Do nothing if profiling has stopped. + if (startTime == null || (endTime != null && endTime.isAfter(startTime))) { return; } @@ -138,7 +141,7 @@ public static void addQuery(Type type, String sql, long time) { switch (type) { case select: selectCount++; - totalSelectTime += time; + totalSelectTime = totalSelectTime.plus(time); entry = selectQueries.get(sql); if (entry == null) { entry = new ProfiledConnectionEntry(sql); @@ -147,7 +150,7 @@ public static void addQuery(Type type, String sql, long time) { break; case update: updateCount++; - totalUpdateTime += time; + totalUpdateTime = totalUpdateTime.plus(time); entry = updateQueries.get(sql); if (entry == null) { entry = new ProfiledConnectionEntry(sql); @@ -156,7 +159,7 @@ public static void addQuery(Type type, String sql, long time) { break; case insert: insertCount++; - totalInsertTime += time; + totalInsertTime = totalInsertTime.plus(time); entry = insertQueries.get(sql); if (entry == null) { entry = new ProfiledConnectionEntry(sql); @@ -165,7 +168,7 @@ public static void addQuery(Type type, String sql, long time) { break; case delete: deleteCount++; - totalDeleteTime += time; + totalDeleteTime = totalDeleteTime.plus(time); entry = deleteQueries.get(sql); if (entry == null) { entry = new ProfiledConnectionEntry(sql); @@ -177,7 +180,7 @@ public static void addQuery(Type type, String sql, long time) { } entry.count++; - entry.totalTime += time; + entry.totalTime = entry.totalTime.plus(time); } /** @@ -202,13 +205,18 @@ public static double getQueriesPerSecond(Type type) { if (count == 0) { return 0; } + + if (startTime == null) { + return 0; + } + // If the profiling hasn't been stopped yet, we want to give // profiling values up to the current time instead. - if (endTime == 0) { - endTime = System.currentTimeMillis(); - } + Instant end = endTime == null ? Instant.now() : endTime; + // Compute the number of seconds - double time = (endTime - startTime) / 1000.0; + double time = Duration.between(startTime, end).toMillis() / 1000.0; + // Finally, return the average. return count / time; } @@ -221,8 +229,9 @@ public static double getQueriesPerSecond(Type type) { * @return a double representing the average time spent executing the type * of query. */ - public static double getAverageQueryTime(Type type) { - long time, count; + public static Duration getAverageQueryTime(Type type) { + Duration time; + long count; switch (type) { case select: @@ -246,10 +255,10 @@ public static double getAverageQueryTime(Type type) { } if (count != 0) { - return time / (double)count; + return time.dividedBy(count); } else { - return 0.0; + return Duration.ZERO; } } @@ -262,7 +271,7 @@ public static double getAverageQueryTime(Type type) { * @return the number of milliseconds spent executing the specified type of * query. */ - public static long getTotalQueryTime(Type type) { + public static Duration getTotalQueryTime(Type type) { return switch (type) { case select -> totalSelectTime; case update -> totalUpdateTime; @@ -303,10 +312,14 @@ public static ProfiledConnectionEntry[] getSortedQueries(Type type, boolean sort * Reset all statistics. */ public static void resetStatistics() { - startTime = 0; - endTime = 0; + final boolean isRunning = startTime != null && (endTime == null || startTime.isAfter(endTime)); + startTime = isRunning ? Instant.now() : null; + endTime = null; insertCount = updateCount = selectCount = deleteCount = 0; - totalInsertTime = totalUpdateTime = totalSelectTime = totalDeleteTime = 0; + totalInsertTime = Duration.ZERO; + totalUpdateTime = Duration.ZERO; + totalSelectTime = Duration.ZERO; + totalDeleteTime = Duration.ZERO; insertQueries.clear(); updateQueries.clear(); @@ -331,7 +344,7 @@ private static void quickSort(ProfiledConnectionEntry[] entries, boolean sortByT int index = first; for (int i = first + 1; i <= last; i++) { - if (sortByTime && ((entries[first].totalTime / entries[first].count) < (entries[i].totalTime / entries[i].count))) { + if (sortByTime && ((entries[first].totalTime.dividedBy(entries[first].count)).compareTo(entries[i].totalTime.dividedBy(entries[i].count))) < 0) { swap(entries, ++index, i); } else if (!sortByTime && entries[first].count < entries[i].count) { @@ -536,70 +549,70 @@ public TimedStatement(Statement stmt) { public boolean execute(String sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); boolean result = stmt.execute(sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); } else { - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); } return result; } public ResultSet executeQuery(String sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); ResultSet result = stmt.executeQuery(sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); } else { - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); } return result; } public int executeUpdate(String sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); int result = stmt.executeUpdate(sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); } else { - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); } return result; } @@ -638,22 +651,22 @@ else if (sqlL.startsWith("delete")) { public boolean execute() throws SQLException { // Perform timing of this method. - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); boolean result = pstmt.execute(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -664,22 +677,22 @@ public boolean execute() throws SQLException { */ public ResultSet executeQuery() throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); ResultSet result = pstmt.executeQuery(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -690,22 +703,22 @@ public ResultSet executeQuery() throws SQLException { */ public int executeUpdate() throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); int result = pstmt.executeUpdate(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -717,94 +730,94 @@ public int executeUpdate() throws SQLException { public boolean execute(String _sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); boolean result = pstmt.execute(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } public int[] executeBatch() throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); int[] result = pstmt.executeBatch(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; } public ResultSet executeQuery(String _sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); ResultSet result = pstmt.executeQuery(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } public int executeUpdate(String _sql) throws SQLException { - long t1 = System.currentTimeMillis(); + Instant start = Instant.now(); int result = pstmt.executeUpdate(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } @@ -841,24 +854,24 @@ else if (sqlL.startsWith("delete")) { } } - public boolean execute() throws SQLException { - // Perform timing of this method. - long t1 = System.currentTimeMillis(); + public boolean execute() throws SQLException + { + Instant start = Instant.now(); boolean result = cstmt.execute(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -867,24 +880,24 @@ public boolean execute() throws SQLException { /* * This is one of the methods that we wish to time */ - public ResultSet executeQuery() throws SQLException { - - long t1 = System.currentTimeMillis(); + public ResultSet executeQuery() throws SQLException + { + Instant start = Instant.now(); ResultSet result = cstmt.executeQuery(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -893,24 +906,24 @@ public ResultSet executeQuery() throws SQLException { /* * This is one of the methods that we wish to time */ - public int executeUpdate() throws SQLException { - - long t1 = System.currentTimeMillis(); + public int executeUpdate() throws SQLException + { + Instant start = Instant.now(); int result = cstmt.executeUpdate(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; @@ -920,96 +933,97 @@ public int executeUpdate() throws SQLException { // SuperInterface of PreparedStatement // without these this class won't compile - public boolean execute(String _sql) throws SQLException { - - long t1 = System.currentTimeMillis(); + public boolean execute(String _sql) throws SQLException + { + Instant start = Instant.now(); boolean result = cstmt.execute(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } - public int[] executeBatch() throws SQLException { - - long t1 = System.currentTimeMillis(); + public int[] executeBatch() throws SQLException + { + Instant start = Instant.now(); int[] result = cstmt.executeBatch(); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); switch (type) { case select: - addQuery(Type.select, sql, t2 - t1); + addQuery(Type.select, sql, Duration.between(start, end)); break; case update: - addQuery(Type.update, sql, t2 - t1); + addQuery(Type.update, sql, Duration.between(start, end)); break; case insert: - addQuery(Type.insert, sql, t2 - t1); + addQuery(Type.insert, sql, Duration.between(start, end)); break; case delete: - addQuery(Type.delete, sql, t2 - t1); + addQuery(Type.delete, sql, Duration.between(start, end)); break; } return result; } - public ResultSet executeQuery(String _sql) throws SQLException { - long t1 = System.currentTimeMillis(); + public ResultSet executeQuery(String _sql) throws SQLException + { + Instant start = Instant.now(); ResultSet result = cstmt.executeQuery(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } - public int executeUpdate(String _sql) throws SQLException { - - long t1 = System.currentTimeMillis(); + public int executeUpdate(String _sql) throws SQLException + { + Instant start = Instant.now(); int result = cstmt.executeUpdate(_sql); - long t2 = System.currentTimeMillis(); + Instant end = Instant.now(); // determine the type of query String sqlL = _sql.toLowerCase().trim(); if (sqlL.startsWith("insert")) { - addQuery(Type.insert, _sql, t2 - t1); + addQuery(Type.insert, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("update")) { - addQuery(Type.update, _sql, t2 - t1); + addQuery(Type.update, _sql, Duration.between(start, end)); } else if (sqlL.startsWith("delete")) { - addQuery(Type.delete, _sql, t2 - t1); + addQuery(Type.delete, _sql, Duration.between(start, end)); } else { - addQuery(Type.select, _sql, t2 - t1); + addQuery(Type.select, _sql, Duration.between(start, end)); } return result; } diff --git a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java index 9988d828b7..a0f4deffd5 100644 --- a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java +++ b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java @@ -16,6 +16,8 @@ package org.jivesoftware.database; +import java.time.Duration; + /** * Simple class for tracking profiling stats for individual SQL queries. * @@ -33,13 +35,13 @@ public class ProfiledConnectionEntry { public int count; /** - * The total time spent executing the query (in milliseconds). + * The total time spent executing the query. */ - public long totalTime; + public Duration totalTime; public ProfiledConnectionEntry(String sql) { this.sql = sql; count = 0; - totalTime = 0; + totalTime = Duration.ZERO; } } diff --git a/xmppserver/src/main/webapp/server-db-stats.jsp b/xmppserver/src/main/webapp/server-db-stats.jsp index 2a5650055a..04f69bde66 100644 --- a/xmppserver/src/main/webapp/server-db-stats.jsp +++ b/xmppserver/src/main/webapp/server-db-stats.jsp @@ -187,11 +187,11 @@ - <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select)) %> + <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select).toMillis()) %> - <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select)) %> + <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select).toMillis()) %> @@ -228,8 +228,8 @@ ProfiledConnectionEntry pce = list[i]; out.println("" + pce.sql + ""); out.println("" + intFormat.format(pce.count) + ""); - out.println("" + intFormat.format(pce.totalTime) + ""); - out.println("" + intFormat.format(pce.totalTime/pce.count) + ""); + out.println("" + intFormat.format(pce.totalTime.toMillis()) + ""); + out.println("" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + ""); } out.println(""); } @@ -254,11 +254,11 @@ - <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.insert)) %> + <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.insert).toMillis()) %> - <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.insert)) %> + <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.insert).toMillis()) %> @@ -295,8 +295,8 @@ ProfiledConnectionEntry pce = list[i]; out.println("" + pce.sql + ""); out.println("" + intFormat.format(pce.count) + ""); - out.println("" + intFormat.format(pce.totalTime) + ""); - out.println("" + intFormat.format(pce.totalTime/pce.count) + ""); + out.println("" + intFormat.format(pce.totalTime.toMillis()) + ""); + out.println("" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + ""); } out.println(""); } @@ -321,11 +321,11 @@ - <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.update)) %> + <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.update).toMillis()) %> - <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.update)) %> + <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.update).toMillis()) %> @@ -362,8 +362,8 @@ ProfiledConnectionEntry pce = list[i]; out.println("" + pce.sql + ""); out.println("" + intFormat.format(pce.count) + ""); - out.println("" + intFormat.format(pce.totalTime) + ""); - out.println("" + intFormat.format(pce.totalTime/pce.count) + ""); + out.println("" + intFormat.format(pce.totalTime.toMillis()) + ""); + out.println("" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + ""); } out.println(""); } @@ -388,11 +388,11 @@ - <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.delete)) %> + <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.delete).toMillis()) %> - <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.delete)) %> + <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.delete).toMillis()) %> @@ -429,8 +429,8 @@ ProfiledConnectionEntry pce = list[i]; out.println("" + pce.sql + ""); out.println("" + intFormat.format(pce.count) + ""); - out.println("" + intFormat.format(pce.totalTime) + ""); - out.println("" + intFormat.format(pce.totalTime/pce.count) + ""); + out.println("" + intFormat.format(pce.totalTime.toMillis()) + ""); + out.println("" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + ""); } out.println(""); } diff --git a/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java b/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java index 1ae1f70656..1e91ceda0c 100644 --- a/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java +++ b/xmppserver/src/test/java/org/jivesoftware/database/ProfiledConnectionTest.java @@ -16,10 +16,11 @@ package org.jivesoftware.database; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Duration; + import static org.junit.jupiter.api.Assertions.*; /** @@ -47,12 +48,12 @@ public void testAverageQueryTime() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); - final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(4)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(6)); + final Duration result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); // Verify results. - assertEquals(5, result); + assertEquals(Duration.ofMillis(5), result); } @Test @@ -88,8 +89,8 @@ public void testQueriesPerSecondStartedNotStopped() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(4)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(4)); final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); // Verify results. @@ -103,8 +104,8 @@ public void testQueriesPerSecondStartedAndStopped() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 4); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 6); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(4)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(6)); final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); // Verify results. @@ -118,11 +119,11 @@ public void testAverageQueryTimeCollectedWhenProfiling() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); - final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); + final Duration result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); // Verify results. - assertEquals(2, result); + assertEquals(Duration.ofMillis(2), result); } @Test @@ -132,11 +133,11 @@ public void testAverageQueryTimeNotCollectedWhenNotProfiling() throws Exception ProfiledConnection.stop(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); - final double result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); + final Duration result = ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select); // Verify results. - assertEquals(0, result); + assertEquals(Duration.ZERO, result); } @Test @@ -146,7 +147,7 @@ public void testQueriesPerSecondCollectedWhenProfiling() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); // Verify results. @@ -160,7 +161,7 @@ public void testQueriesPerSecondNotCollectedWhenNotProfiling() throws Exception ProfiledConnection.stop(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); final double result = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); // Verify results. @@ -174,7 +175,7 @@ public void testQueryCountCollectedWhenProfiling() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); // Verify results. @@ -188,7 +189,7 @@ public void testQueryCountNotCollectedWhenNotProfiling() throws Exception ProfiledConnection.stop(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); // Verify results. @@ -202,11 +203,11 @@ public void testTotalQueryTimeCollectedWhenProfiling() throws Exception ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); - final double result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); + final Duration result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); // Verify results. - assertEquals(2, result); + assertEquals(Duration.ofMillis(2), result); } @Test @@ -216,11 +217,11 @@ public void testTotalQueryTimeNotCollectedWhenNotProfiling() throws Exception ProfiledConnection.stop(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); - final double result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); + final Duration result = ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select); // Verify results. - assertEquals(0, result); + assertEquals(Duration.ZERO, result); } @Test @@ -228,8 +229,8 @@ public void testStatsDontResetAtStop() throws Exception { // Setup test fixture. ProfiledConnection.start(); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(3)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(1)); ProfiledConnection.stop(); // Execute system under test. @@ -244,13 +245,13 @@ public void testStartResetsStatistics() { // Setup test fixture. ProfiledConnection.start(); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(3)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(1)); ProfiledConnection.stop(); ProfiledConnection.start(); // Execute system under test. - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 2); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(2)); final double result = ProfiledConnection.getQueryCount(ProfiledConnection.Type.select); // Verify results. @@ -262,8 +263,8 @@ public void testQueriesPerSecondCalculatedBasedOnEndTime() throws Exception { // Setup test fixture. ProfiledConnection.start(); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 3); - ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", 1); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(3)); + ProfiledConnection.addQuery(ProfiledConnection.Type.select, "SELECT 1", Duration.ofMillis(1)); Thread.sleep(5); // To prevent 'infinity' final double expected = ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select); ProfiledConnection.stop(); From 4e247b9298565c8731a22838aae0883f4d1241f7 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Mon, 25 Nov 2024 21:22:26 +0100 Subject: [PATCH 4/4] Update Database Query Statistics page Mostly converts the page from scriptlet to JSTL. Makes the tables that contain SQL wider Other minor CSS tweaks. --- .../main/resources/openfire_i18n.properties | 2 +- .../resources/openfire_i18n_cs_CZ.properties | 1 - .../resources/openfire_i18n_de.properties | 1 - .../resources/openfire_i18n_es.properties | 1 - .../resources/openfire_i18n_fa_IR.properties | 1 - .../resources/openfire_i18n_he.properties | 1 - .../resources/openfire_i18n_ja_JP.properties | 1 - .../resources/openfire_i18n_nl.properties | 38 +- .../resources/openfire_i18n_pl_PL.properties | 1 - .../resources/openfire_i18n_pt_BR.properties | 1 - .../resources/openfire_i18n_pt_PT.properties | 1 - .../resources/openfire_i18n_ru_RU.properties | 1 - .../resources/openfire_i18n_sk.properties | 1 - .../resources/openfire_i18n_uk_UA.properties | 1 - .../resources/openfire_i18n_zh_CN.properties | 1 - .../database/ProfiledConnectionEntry.java | 34 + .../src/main/webapp/server-db-stats.jsp | 664 ++++++++++-------- 17 files changed, 415 insertions(+), 336 deletions(-) diff --git a/i18n/src/main/resources/openfire_i18n.properties b/i18n/src/main/resources/openfire_i18n.properties index 291a4e6f8e..ffae627e32 100644 --- a/i18n/src/main/resources/openfire_i18n.properties +++ b/i18n/src/main/resources/openfire_i18n.properties @@ -1185,10 +1185,10 @@ server.db_stats.enabled=Enabled server.db_stats.disabled=Disabled server.db_stats.update=Update server.db_stats.refresh=Refresh +server.db_stats.refresh_now=Refresh Now server.db_stats.none=none server.db_stats.settings=Query Statistics Settings server.db_stats.seconds=seconds -server.db_stats.set=Set server.db_stats.clear_stats=Clear All Stats server.db_stats.select_stats=SELECT Query Statistics server.db_stats.insert_stats=INSERT Query Statistics diff --git a/i18n/src/main/resources/openfire_i18n_cs_CZ.properties b/i18n/src/main/resources/openfire_i18n_cs_CZ.properties index d81d3b8cf4..2a9d43db79 100644 --- a/i18n/src/main/resources/openfire_i18n_cs_CZ.properties +++ b/i18n/src/main/resources/openfire_i18n_cs_CZ.properties @@ -862,7 +862,6 @@ server.db_stats.refresh=Občerstvit server.db_stats.none=žádná server.db_stats.settings=Nastavení statistiky dotazů server.db_stats.seconds=sekundy -server.db_stats.set=Nastavit server.db_stats.clear_stats=Vymazat všechny statistiky server.db_stats.select_stats=Statistika SELECT dotazů server.db_stats.insert_stats=Statistika INSERT dotazů diff --git a/i18n/src/main/resources/openfire_i18n_de.properties b/i18n/src/main/resources/openfire_i18n_de.properties index b50fa42347..2894f5435a 100644 --- a/i18n/src/main/resources/openfire_i18n_de.properties +++ b/i18n/src/main/resources/openfire_i18n_de.properties @@ -1113,7 +1113,6 @@ server.db_stats.query=Anfrage server.db_stats.refresh=Aktualisieren server.db_stats.seconds=Sekunden server.db_stats.select_stats=SELECT Anfragestatistiken -server.db_stats.set=Festlegen server.db_stats.settings=Anfragestatistik-Einstellungen server.db_stats.status=Anfragestatistik-Status server.db_stats.time=Gesamtzeit diff --git a/i18n/src/main/resources/openfire_i18n_es.properties b/i18n/src/main/resources/openfire_i18n_es.properties index afd9cadbb9..a0d20ca932 100644 --- a/i18n/src/main/resources/openfire_i18n_es.properties +++ b/i18n/src/main/resources/openfire_i18n_es.properties @@ -1089,7 +1089,6 @@ server.db_stats.refresh=Refrescar server.db_stats.none=nunca server.db_stats.settings=Configuración de Estadísticas de Consultas server.db_stats.seconds=segundos -server.db_stats.set=Setear server.db_stats.clear_stats=Resetear Estadísticas server.db_stats.select_stats=Estadísticas de SELECT server.db_stats.insert_stats=Estadísticas de INSERT diff --git a/i18n/src/main/resources/openfire_i18n_fa_IR.properties b/i18n/src/main/resources/openfire_i18n_fa_IR.properties index 087420dcd3..00de10e1dc 100644 --- a/i18n/src/main/resources/openfire_i18n_fa_IR.properties +++ b/i18n/src/main/resources/openfire_i18n_fa_IR.properties @@ -1078,7 +1078,6 @@ server.db_stats.refresh=بارگذاری مجدد server.db_stats.none=هیچ server.db_stats.settings=تنظیمات آمار کوئری server.db_stats.seconds=ثانیه -server.db_stats.set=تنظیم server.db_stats.clear_stats=پاک کردن تمام آمار server.db_stats.select_stats=آمار کوئری SELECT server.db_stats.insert_stats=آمار کوئری INSERT diff --git a/i18n/src/main/resources/openfire_i18n_he.properties b/i18n/src/main/resources/openfire_i18n_he.properties index 117529b4d4..df150e936a 100644 --- a/i18n/src/main/resources/openfire_i18n_he.properties +++ b/i18n/src/main/resources/openfire_i18n_he.properties @@ -1076,7 +1076,6 @@ server.db_stats.refresh=רענן server.db_stats.none=none server.db_stats.settings=Query Statistics Settings server.db_stats.seconds=שניות -server.db_stats.set=Set server.db_stats.clear_stats=טהר את כל הסטטיסטיקה server.db_stats.select_stats=SELECT Query Statistics server.db_stats.insert_stats=INSERT Query Statistics diff --git a/i18n/src/main/resources/openfire_i18n_ja_JP.properties b/i18n/src/main/resources/openfire_i18n_ja_JP.properties index e79eb73529..f96a5b818b 100644 --- a/i18n/src/main/resources/openfire_i18n_ja_JP.properties +++ b/i18n/src/main/resources/openfire_i18n_ja_JP.properties @@ -859,7 +859,6 @@ server.db_stats.refresh=リフレッシュ server.db_stats.none=なし server.db_stats.settings=クエリー統計設定 server.db_stats.seconds=秒 -server.db_stats.set=セット server.db_stats.clear_stats=全統計のクリアー server.db_stats.select_stats=SELECTクエリー統計 server.db_stats.insert_stats=INSERTクエリー統計 diff --git a/i18n/src/main/resources/openfire_i18n_nl.properties b/i18n/src/main/resources/openfire_i18n_nl.properties index 0e25ad5b53..92ac446cf7 100644 --- a/i18n/src/main/resources/openfire_i18n_nl.properties +++ b/i18n/src/main/resources/openfire_i18n_nl.properties @@ -1067,32 +1067,32 @@ server.db.test_timeout=Test Timeout: server.db.connection_mean_borrow_time=Average time waited: server.db.connection_max_borrow_time=Max time waited: -server.db_stats.title=Database Query Statistics +server.db_stats.title=Database Query Statistieken server.db_stats.description=Enable database query statistics to trace all database queries made. This can be useful to debug issues and monitor database performance. However, it's not recommended that you leave query statistics permanently running, as they will cause performance to degrade slightly. server.db_stats.status=Query Statistics Status server.db_stats.enabled=Ingeschakeld server.db_stats.disabled=Uitgeschakeld server.db_stats.update=Update -server.db_stats.refresh=Refresh -server.db_stats.none=none -server.db_stats.settings=Query Statistics Settings -server.db_stats.seconds=seconds -server.db_stats.set=Set +server.db_stats.refresh=Ververs +server.db_stats.refresh_now=Ververs Nu +server.db_stats.none=geen +server.db_stats.settings=Query Statistics Configuratie +server.db_stats.seconds=seconden server.db_stats.clear_stats=Clear All Stats -server.db_stats.select_stats=SELECT Query Statistics -server.db_stats.insert_stats=INSERT Query Statistics -server.db_stats.update_stats=UPDATE Query Statistics -server.db_stats.delete_stats=DELETE Query Statistics -server.db_stats.operations=Total # of operations -server.db_stats.total_time=Total time for all operations (ms) -server.db_stats.avg_rate=Average time for each operation (ms) -server.db_stats.total_rate=Operations per second -server.db_stats.queries=Most common SQL queries +server.db_stats.select_stats=SELECT Query Statistieken +server.db_stats.insert_stats=INSERT Query Statistieken +server.db_stats.update_stats=UPDATE Query Statistieken +server.db_stats.delete_stats=DELETE Query Statistieken +server.db_stats.operations=Totaal # operaties +server.db_stats.total_time=Totale tijd voor alle operaties (ms) +server.db_stats.avg_rate=Gemiddelde time voor een operatie (ms) +server.db_stats.total_rate=Operaties per seconde +server.db_stats.queries=Meestgebruikte SQL queries server.db_stats.query=Query -server.db_stats.count=Count -server.db_stats.time=Total Time -server.db_stats.average_time=Avg. Time -server.db_stats.no_queries=No queries +server.db_stats.count=Aantal +server.db_stats.time=Totaal Tijd +server.db_stats.average_time=Gem. Tijd +server.db_stats.no_queries=Geen queries # diff --git a/i18n/src/main/resources/openfire_i18n_pl_PL.properties b/i18n/src/main/resources/openfire_i18n_pl_PL.properties index c6b6215eee..c2f203e517 100644 --- a/i18n/src/main/resources/openfire_i18n_pl_PL.properties +++ b/i18n/src/main/resources/openfire_i18n_pl_PL.properties @@ -2150,7 +2150,6 @@ server.db_stats.query=Query server.db_stats.refresh=Refresh server.db_stats.seconds=seconds server.db_stats.select_stats=SELECT Query Statistics -server.db_stats.set=Set server.db_stats.settings=Query Statistics Settings server.db_stats.status=Query Statistics Status server.db_stats.time=Total Time diff --git a/i18n/src/main/resources/openfire_i18n_pt_BR.properties b/i18n/src/main/resources/openfire_i18n_pt_BR.properties index d53fd76a61..3818dae1d3 100644 --- a/i18n/src/main/resources/openfire_i18n_pt_BR.properties +++ b/i18n/src/main/resources/openfire_i18n_pt_BR.properties @@ -859,7 +859,6 @@ server.db_stats.refresh=Atualizar server.db_stats.none=nenhum server.db_stats.settings=Configurações das Estatísticas de Consulta server.db_stats.seconds=segundos -server.db_stats.set=Definir server.db_stats.clear_stats=Limpar todas as estatísticas server.db_stats.select_stats=Estatística de Consulta SELECT server.db_stats.insert_stats=Estatística de Consulta INSERT diff --git a/i18n/src/main/resources/openfire_i18n_pt_PT.properties b/i18n/src/main/resources/openfire_i18n_pt_PT.properties index 4c978eee34..c8dbb3d713 100644 --- a/i18n/src/main/resources/openfire_i18n_pt_PT.properties +++ b/i18n/src/main/resources/openfire_i18n_pt_PT.properties @@ -953,7 +953,6 @@ server.db_stats.refresh=Atualizar server.db_stats.none=Nenhum server.db_stats.settings=Configurações das Estatísticas de Consulta server.db_stats.seconds=segundos -server.db_stats.set=Definir server.db_stats.clear_stats=Limpar todas as estatísticas server.db_stats.select_stats=Estatística de Consulta SELECT server.db_stats.insert_stats=Estatística de Consulta INSERT diff --git a/i18n/src/main/resources/openfire_i18n_ru_RU.properties b/i18n/src/main/resources/openfire_i18n_ru_RU.properties index 70066a9d4f..d2040195d0 100644 --- a/i18n/src/main/resources/openfire_i18n_ru_RU.properties +++ b/i18n/src/main/resources/openfire_i18n_ru_RU.properties @@ -1035,7 +1035,6 @@ server.db_stats.refresh=Обновлять server.db_stats.none=никогда server.db_stats.settings=Настройки статистики запросов server.db_stats.seconds=секунд -server.db_stats.set=Задать server.db_stats.clear_stats=Очистить всю статистику server.db_stats.select_stats=SELECT статистика запросов server.db_stats.insert_stats=INSERT статистика запросов diff --git a/i18n/src/main/resources/openfire_i18n_sk.properties b/i18n/src/main/resources/openfire_i18n_sk.properties index cf889973e0..402ec94341 100644 --- a/i18n/src/main/resources/openfire_i18n_sk.properties +++ b/i18n/src/main/resources/openfire_i18n_sk.properties @@ -837,7 +837,6 @@ server.db_stats.refresh=Obnoviť server.db_stats.none=žiadne server.db_stats.settings=Nastavenia štatistiky požiadaviek server.db_stats.seconds=sekúnd -server.db_stats.set=Nastavenie server.db_stats.clear_stats=Vyčistiť všetky štatistiky server.db_stats.select_stats=Štatistika požiadaviek SELECT server.db_stats.insert_stats=Štatistika požiadaviek INSERT diff --git a/i18n/src/main/resources/openfire_i18n_uk_UA.properties b/i18n/src/main/resources/openfire_i18n_uk_UA.properties index 68b4168eec..b9ae0dbcce 100644 --- a/i18n/src/main/resources/openfire_i18n_uk_UA.properties +++ b/i18n/src/main/resources/openfire_i18n_uk_UA.properties @@ -1076,7 +1076,6 @@ server.db_stats.refresh=Оновити server.db_stats.none=жодного server.db_stats.settings=Налаштування статистики запиту server.db_stats.seconds=секунд -server.db_stats.set=Встановити server.db_stats.clear_stats=Очистити всю статистику server.db_stats.select_stats=ОБЕРІТЬ статистику запиту server.db_stats.insert_stats=ВСТАВИТИ статистику запиту diff --git a/i18n/src/main/resources/openfire_i18n_zh_CN.properties b/i18n/src/main/resources/openfire_i18n_zh_CN.properties index 9205662a59..fc52b6a120 100644 --- a/i18n/src/main/resources/openfire_i18n_zh_CN.properties +++ b/i18n/src/main/resources/openfire_i18n_zh_CN.properties @@ -1113,7 +1113,6 @@ server.db_stats.refresh=刷新 server.db_stats.none=没有 server.db_stats.settings=查询统计数据设置 server.db_stats.seconds=秒 -server.db_stats.set=设置 server.db_stats.clear_stats=清除所有统计数据 server.db_stats.select_stats=选择查询统计数据 server.db_stats.insert_stats=插入查询统计数据 diff --git a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java index a0f4deffd5..746dd042fb 100644 --- a/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java +++ b/xmppserver/src/main/java/org/jivesoftware/database/ProfiledConnectionEntry.java @@ -44,4 +44,38 @@ public ProfiledConnectionEntry(String sql) { count = 0; totalTime = Duration.ZERO; } + + public String getSql() + { + return sql; + } + + public void setSql(String sql) + { + this.sql = sql; + } + + public int getCount() + { + return count; + } + + public void setCount(int count) + { + this.count = count; + } + + public Duration getTotalTime() + { + return totalTime; + } + + public void setTotalTime(Duration totalTime) + { + this.totalTime = totalTime; + } + + public Duration getAverageTime() { + return this.totalTime.dividedBy(count); + } } diff --git a/xmppserver/src/main/webapp/server-db-stats.jsp b/xmppserver/src/main/webapp/server-db-stats.jsp index 04f69bde66..33d42d1fb4 100644 --- a/xmppserver/src/main/webapp/server-db-stats.jsp +++ b/xmppserver/src/main/webapp/server-db-stats.jsp @@ -1,7 +1,7 @@ <%@ page contentType="text/html; charset=UTF-8" %> <%-- - - - Copyright (C) 2004-2008 Jive Software, 2016-2022 Ignite Realtime Foundation. All rights reserved. + - Copyright (C) 2004-2008 Jive Software, 2016-2024 Ignite Realtime Foundation. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ --%> <%@ page import="java.text.*" - errorPage="error.jsp" + errorPage="error.jsp" %> <%@ page import="org.jivesoftware.database.DbConnectionManager"%> <%@ page import="org.jivesoftware.util.JiveGlobals"%> @@ -30,6 +30,7 @@ <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> +<%@ taglib uri="admin" prefix="admin" %> <% webManager.init(request, response, session, application, out ); %> @@ -82,367 +83,424 @@ } } - boolean showQueryStats = DbConnectionManager.isProfilingEnabled(); - // Number intFormat for pretty printing of large number values and decimals: NumberFormat intFormat = NumberFormat.getInstance(JiveGlobals.getLocale()); DecimalFormat decFormat = new DecimalFormat("#,##0.00"); + + pageContext.setAttribute("refresh", refresh); + pageContext.setAttribute("profilingEnabled", DbConnectionManager.isProfilingEnabled()); + pageContext.setAttribute("selectList", ProfiledConnection.getSortedQueries(ProfiledConnection.Type.select, doSortByTime)); + pageContext.setAttribute("insertList", ProfiledConnection.getSortedQueries(ProfiledConnection.Type.insert, doSortByTime)); + pageContext.setAttribute("updateList", ProfiledConnection.getSortedQueries(ProfiledConnection.Type.update, doSortByTime)); + pageContext.setAttribute("deleteList", ProfiledConnection.getSortedQueries(ProfiledConnection.Type.delete, doSortByTime)); %> - - <fmt:message key="server.db_stats.title" /> - + + <fmt:message key="server.db_stats.title" /> + <% // Enable refreshing if specified if (refresh >= 10) { %> - + <% } %> +

- +

- - -
-

- -
- - - - - - - -
- > - - - > - - - "> -
-
+

-<% if (showQueryStats) { %> +
+ + + + + + + +
+ + + + + + + "> +
+
+ +

- - + - - - - - - + <% } %> + + + + + + +
- : -
+ : + - - "> - | - "> - | - "> -
| + "> + | + "> +
- + -
    +
      - -
      - - - - - - - - - - - - - - - - - - - - - -
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.select)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select)) %>
      <% - ProfiledConnectionEntry[] list = ProfiledConnection.getSortedQueries(ProfiledConnection.Type.select, doSortByTime); - - if (list == null || list.length < 1) { - out.println(LocaleUtils.getLocalizedString("server.db_stats.no_queries")); - } - else { %> -   -
      -
      - -
      - - - +
      - - - -
      - <% out.println(""); - out.println(""); - out.println(""); - out.println(""); - - for ( int i = 0; i < (Math.min(list.length, 20)); i++) { - ProfiledConnectionEntry pce = list[i]; - out.println(""); - out.println(""); - out.println(""); - out.println(""); - } - out.println("
      " + LocaleUtils.getLocalizedString("server.db_stats.query") + "" + LocaleUtils.getLocalizedString("server.db_stats.count") + "" + LocaleUtils.getLocalizedString("server.db_stats.time") + "" + LocaleUtils.getLocalizedString("server.db_stats.average_time") + "
      " + pce.sql + "" + intFormat.format(pce.count) + "" + intFormat.format(pce.totalTime.toMillis()) + "" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + "
      "); - } - %>
      -
      + + + + + + + + + + + + + + + + + + + + + +
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.select)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.select).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.select).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.select)) %>
      + + + + + +   + + +
      +
      -
    + +
    + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
- + -
    +
      - +
      - - - - - - - - - - - - - - - - - - - - - -
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.insert)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.insert).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.insert).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.insert)) %>
      <% - list = ProfiledConnection.getSortedQueries(ProfiledConnection.Type.insert, doSortByTime); - - if (list == null || list.length < 1) { - out.println(LocaleUtils.getLocalizedString("server.db_stats.no_queries")); - } - else { %> -   -
      -
      + + + + + + + + + + + + + + + + + + + + + +
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.insert)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.insert).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.insert).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.insert)) %>
      + + + + + +   + + +
      +
      -
      - - - -
      - - - -
      - <% out.println(""); - out.println(""); - out.println(""); - out.println(""); - - for ( int i = 0; i < (Math.min(list.length, 10)); i++) { - ProfiledConnectionEntry pce = list[i]; - out.println(""); - out.println(""); - out.println(""); - out.println(""); - } - out.println("
      " + LocaleUtils.getLocalizedString("server.db_stats.query") + "" + LocaleUtils.getLocalizedString("server.db_stats.count") + "" + LocaleUtils.getLocalizedString("server.db_stats.time") + "" + LocaleUtils.getLocalizedString("server.db_stats.average_time") + "
      " + pce.sql + "" + intFormat.format(pce.count) + "" + intFormat.format(pce.totalTime.toMillis()) + "" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + "
      "); - } - %>
      -
      - -
    + +
    + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
- + -
    +
      - +
      - - - - - - - - - - - - - - - - - - - - - -
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.update)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.update).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.update).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.update)) %>
      <% - list = ProfiledConnection.getSortedQueries(ProfiledConnection.Type.update, doSortByTime); - - if (list == null || list.length < 1) { - out.println(LocaleUtils.getLocalizedString("server.db_stats.no_queries")); - } - else { %> -   -
      -
      + + + + + + + + + + + + + + + + + + + + + +
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.update)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.update).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.update).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.update)) %>
      + + + + + +   + + +
      +
      -
      - - - -
      - - - -
      - <% out.println(""); - out.println(""); - out.println(""); - out.println(""); - - for ( int i = 0; i < (Math.min(list.length, 10)); i++) { - ProfiledConnectionEntry pce = list[i]; - out.println(""); - out.println(""); - out.println(""); - out.println(""); - } - out.println("
      " + LocaleUtils.getLocalizedString("server.db_stats.query") + "" + LocaleUtils.getLocalizedString("server.db_stats.count") + "" + LocaleUtils.getLocalizedString("server.db_stats.time") + "" + LocaleUtils.getLocalizedString("server.db_stats.average_time") + "
      " + pce.sql + "" + intFormat.format(pce.count) + "" + intFormat.format(pce.totalTime.toMillis()) + "" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + "
      "); - } - %>
      -
      - -
    - - - -
      + +
      + + + +
      + + +
      + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      +
    - - -
    - - - - - - - - - - - - - - - - - - - - - -
    <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.delete)) %>
    <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.delete).toMillis()) %>
    <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.delete).toMillis()) %>
    <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.delete)) %>
    <% - list = ProfiledConnection.getSortedQueries(ProfiledConnection.Type.delete, doSortByTime); - - if (list == null || list.length < 1) { - out.println(LocaleUtils.getLocalizedString("server.db_stats.no_queries")); - } - else { %> -   -
    -
    + -
    +
      - +
      - - - -
      - <% out.println(""); - out.println(""); - out.println(""); - out.println(""); - - for ( int i = 0; i < (Math.min(list.length, 10)); i++) { - ProfiledConnectionEntry pce = list[i]; - out.println(""); - out.println(""); - out.println(""); - out.println(""); - } - out.println("
      " + LocaleUtils.getLocalizedString("server.db_stats.query") + "" + LocaleUtils.getLocalizedString("server.db_stats.count") + "" + LocaleUtils.getLocalizedString("server.db_stats.time") + "" + LocaleUtils.getLocalizedString("server.db_stats.average_time") + "
      " + pce.sql + "" + intFormat.format(pce.count) + "" + intFormat.format(pce.totalTime.toMillis()) + "" + intFormat.format(pce.totalTime.dividedBy(pce.count).toMillis()) + "
      "); - } - %>
      -
      + + + + + + + + + + + + + + + + + + + + + +
      <%= intFormat.format(ProfiledConnection.getQueryCount(ProfiledConnection.Type.delete)) %>
      <%= intFormat.format(ProfiledConnection.getTotalQueryTime(ProfiledConnection.Type.delete).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getAverageQueryTime(ProfiledConnection.Type.delete).toMillis()) %>
      <%= decFormat.format(ProfiledConnection.getQueriesPerSecond(ProfiledConnection.Type.delete)) %>
      + + + + + +   + + +
      +
      -
    + +
    + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    -<% } %> +
+