From 0ab9c9e47b2a1d5ec00c12076459850603b9aa09 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 7 Aug 2022 23:48:47 -0500 Subject: [PATCH] Recycle JDBC connections idle for more than 60 seconds --- .../storage/mssql/MicrosoftSQLMapStorage.java | 19 ++++++++++++++++--- .../dynmap/storage/mysql/MySQLMapStorage.java | 19 ++++++++++++++++--- .../postgresql/PostgreSQLMapStorage.java | 19 ++++++++++++++++--- .../storage/sqllte/SQLiteMapStorage.java | 18 ++++++++++++++++-- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/storage/mssql/MicrosoftSQLMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/mssql/MicrosoftSQLMapStorage.java index 6cfd3b78..5458660a 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/mssql/MicrosoftSQLMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/mssql/MicrosoftSQLMapStorage.java @@ -49,6 +49,8 @@ public class MicrosoftSQLMapStorage extends MapStorage { protected int port; private static final int POOLSIZE = 5; private Connection[] cpool = new Connection[POOLSIZE]; + private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool + private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout private int cpoolCount = 0; private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -527,12 +529,22 @@ public class MicrosoftSQLMapStorage extends MapStorage { private Connection getConnection() throws SQLException { Connection c = null; synchronized (cpool) { + long now = System.currentTimeMillis(); while (c == null) { for (int i = 0; i < cpool.length; i++) { // See if available connection if (cpool[i] != null) { // Found one - c = cpool[i]; - cpool[i] = null; - break; + // If in pool too long, close it and move on + if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) { + try { cpool[i].close(); } catch (SQLException x) {} + cpool[i] = null; + cpoolCount--; + } + else { // Else, use the connection + c = cpool[i]; + cpool[i] = null; + cpoolLastUseTS[i] = now; + break; + } } } if (c == null) { @@ -565,6 +577,7 @@ public class MicrosoftSQLMapStorage extends MapStorage { for (int i = 0; i < POOLSIZE; i++) { if (cpool[i] == null) { cpool[i] = c; + cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time c = null; // Mark it recovered (no close needed cpool.notifyAll(); break; diff --git a/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java index 7ee16154..ec9c701b 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java @@ -49,6 +49,8 @@ public class MySQLMapStorage extends MapStorage { protected int port; private static final int POOLSIZE = 5; private Connection[] cpool = new Connection[POOLSIZE]; + private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool + private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout private int cpoolCount = 0; private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -647,12 +649,22 @@ public class MySQLMapStorage extends MapStorage { Connection c = null; if (isShutdown) { throw new StorageShutdownException(); } synchronized (cpool) { + long now = System.currentTimeMillis(); while (c == null) { for (int i = 0; i < cpool.length; i++) { // See if available connection if (cpool[i] != null) { // Found one - c = cpool[i]; - cpool[i] = null; - break; + // If in pool too long, close it and move on + if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) { + try { cpool[i].close(); } catch (SQLException x) {} + cpool[i] = null; + cpoolCount--; + } + else { // Else, use the connection + c = cpool[i]; + cpool[i] = null; + cpoolLastUseTS[i] = now; + break; + } } } if (c == null) { @@ -685,6 +697,7 @@ public class MySQLMapStorage extends MapStorage { for (int i = 0; i < POOLSIZE; i++) { if (cpool[i] == null) { cpool[i] = c; + cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time c = null; // Mark it recovered (no close needed cpool.notifyAll(); break; diff --git a/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java index 8db2d4b2..31219594 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java @@ -49,6 +49,8 @@ public class PostgreSQLMapStorage extends MapStorage { private int port; private static final int POOLSIZE = 5; private Connection[] cpool = new Connection[POOLSIZE]; + private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool + private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout private int cpoolCount = 0; private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -571,12 +573,22 @@ public class PostgreSQLMapStorage extends MapStorage { Connection c = null; if (isShutdown) throw new StorageShutdownException(); synchronized (cpool) { + long now = System.currentTimeMillis(); while (c == null) { for (int i = 0; i < cpool.length; i++) { // See if available connection if (cpool[i] != null) { // Found one - c = cpool[i]; - cpool[i] = null; - break; + // If in pool too long, close it and move on + if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) { + try { cpool[i].close(); } catch (SQLException x) {} + cpool[i] = null; + cpoolCount--; + } + else { // Else, use the connection + c = cpool[i]; + cpool[i] = null; + cpoolLastUseTS[i] = now; + break; + } } } if (c == null) { @@ -608,6 +620,7 @@ public class PostgreSQLMapStorage extends MapStorage { for (int i = 0; i < POOLSIZE; i++) { if (cpool[i] == null) { cpool[i] = c; + cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time c = null; // Mark it recovered (no close needed cpool.notifyAll(); break; diff --git a/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java index f0580cef..e90d1f9f 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java @@ -33,6 +33,8 @@ public class SQLiteMapStorage extends MapStorage { private String databaseFile; private static final int POOLSIZE = 1; // SQLite is really not thread safe... 1 at a time works best private Connection[] cpool = new Connection[POOLSIZE]; + private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool + private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout private int cpoolCount = 0; private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -492,11 +494,22 @@ public class SQLiteMapStorage extends MapStorage { throw new StorageShutdownException(); } synchronized (cpool) { + long now = System.currentTimeMillis(); while (c == null) { for (int i = 0; i < cpool.length; i++) { // See if available connection if (cpool[i] != null) { // Found one - c = cpool[i]; - cpool[i] = null; + // If in pool too long, close it and move on + if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) { + try { cpool[i].close(); } catch (SQLException x) {} + cpool[i] = null; + cpoolCount--; + } + else { // Else, use the connection + c = cpool[i]; + cpool[i] = null; + cpoolLastUseTS[i] = now; + break; + } } } if (c == null) { @@ -532,6 +545,7 @@ public class SQLiteMapStorage extends MapStorage { for (int i = 0; i < POOLSIZE; i++) { if (cpool[i] == null) { cpool[i] = c; + cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time c = null; // Mark it recovered (no close needed cpool.notifyAll(); break;