diff --git a/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2PoolImpl.java b/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2PoolImpl.java index cf01b9e5..0f242f5e 100644 --- a/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2PoolImpl.java +++ b/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2PoolImpl.java @@ -33,7 +33,8 @@ public class DB2PoolImpl extends PoolBase implements DB2Pool { public DB2PoolImpl(ContextInternal context, boolean closeVertx, DB2ConnectOptions connectOptions, PoolOptions poolOptions) { super(context.owner(), closeVertx); this.factory = new DB2ConnectionFactory(context.owner(), context, connectOptions); - this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize()); + this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize(), + poolOptions.getConnectionReleaseDelay()); } @Override diff --git a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLPoolImpl.java b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLPoolImpl.java index eaff9cf8..e9204d33 100644 --- a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLPoolImpl.java +++ b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLPoolImpl.java @@ -34,7 +34,8 @@ public class MSSQLPoolImpl extends PoolBase implements MSSQLPool public MSSQLPoolImpl(ContextInternal context, boolean closeVertx, MSSQLConnectOptions connectOptions, PoolOptions poolOptions) { super(context.owner(), closeVertx); this.connectionFactory = new MSSQLConnectionFactory(context.owner(), context, connectOptions); - this.pool = new ConnectionPool(connectionFactory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize()); + this.pool = new ConnectionPool(connectionFactory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize(), + poolOptions.getConnectionReleaseDelay()); } @Override diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLPoolImpl.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLPoolImpl.java index a452355f..1a4d3934 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLPoolImpl.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLPoolImpl.java @@ -29,7 +29,8 @@ public class MySQLPoolImpl extends PoolBase implements MySQLPool public MySQLPoolImpl(ContextInternal context, boolean closeVertx, MySQLConnectOptions connectOptions, PoolOptions poolOptions) { super(context.owner(), closeVertx); this.factory = new MySQLConnectionFactory(context.owner(), context, connectOptions); - this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize()); + this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize(), + poolOptions.getConnectionReleaseDelay()); } @Override diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgPoolImpl.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgPoolImpl.java index a8c04105..817aeeee 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgPoolImpl.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgPoolImpl.java @@ -45,7 +45,8 @@ public class PgPoolImpl extends PoolBase implements PgPool { public PgPoolImpl(ContextInternal context, boolean closeVertx, PgConnectOptions connectOptions, PoolOptions poolOptions) { super(context.owner(), closeVertx); this.factory = new PgConnectionFactory(context.owner(), context, connectOptions); - this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize()); + this.pool = new ConnectionPool(factory, context, poolOptions.getMaxSize(), poolOptions.getMaxWaitQueueSize(), + poolOptions.getConnectionReleaseDelay()); if (context.deploymentID() != null) { contextHook = context; diff --git a/vertx-sql-client/src/main/asciidoc/dataobjects.adoc b/vertx-sql-client/src/main/asciidoc/dataobjects.adoc index 886fe321..bbaf1884 100644 --- a/vertx-sql-client/src/main/asciidoc/dataobjects.adoc +++ b/vertx-sql-client/src/main/asciidoc/dataobjects.adoc @@ -12,6 +12,9 @@ [frame="topbot"] |=== ^|Name | Type ^| Description +|[[connectionReleaseDelay]]`@connectionReleaseDelay`|`Number (int)`|+++ +Set the delay in milliseconds before idle connections are closed ++++ |[[maxSize]]`@maxSize`|`Number (int)`|+++ Set the maximum pool size +++ diff --git a/vertx-sql-client/src/main/generated/io/vertx/sqlclient/PoolOptionsConverter.java b/vertx-sql-client/src/main/generated/io/vertx/sqlclient/PoolOptionsConverter.java index 08eaaca0..0e11c5e3 100644 --- a/vertx-sql-client/src/main/generated/io/vertx/sqlclient/PoolOptionsConverter.java +++ b/vertx-sql-client/src/main/generated/io/vertx/sqlclient/PoolOptionsConverter.java @@ -15,6 +15,11 @@ public class PoolOptionsConverter { public static void fromJson(Iterable> json, PoolOptions obj) { for (java.util.Map.Entry member : json) { switch (member.getKey()) { + case "connectionReleaseDelay": + if (member.getValue() instanceof Number) { + obj.setConnectionReleaseDelay(((Number)member.getValue()).intValue()); + } + break; case "maxSize": if (member.getValue() instanceof Number) { obj.setMaxSize(((Number)member.getValue()).intValue()); @@ -34,6 +39,7 @@ public class PoolOptionsConverter { } public static void toJson(PoolOptions obj, java.util.Map json) { + json.put("connectionReleaseDelay", obj.getConnectionReleaseDelay()); json.put("maxSize", obj.getMaxSize()); json.put("maxWaitQueueSize", obj.getMaxWaitQueueSize()); } diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/PoolOptions.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/PoolOptions.java index 71b02a77..3c45e7b4 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/PoolOptions.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/PoolOptions.java @@ -28,6 +28,11 @@ import io.vertx.core.json.JsonObject; @DataObject(generateConverter = true) public class PoolOptions { + /** + * The default connection release delay in milliseconds + */ + public static final int DEFAULT_CONNECTION_RELEASE_DELAY = 60000; + /** * The default maximum number of connections a client will pool = 4 */ @@ -38,6 +43,7 @@ public class PoolOptions { */ public static final int DEFAULT_MAX_WAIT_QUEUE_SIZE = -1; + private int connectionReleaseDelay = DEFAULT_CONNECTION_RELEASE_DELAY; private int maxSize = DEFAULT_MAX_SIZE; private int maxWaitQueueSize = DEFAULT_MAX_WAIT_QUEUE_SIZE; @@ -49,10 +55,29 @@ public class PoolOptions { } public PoolOptions(PoolOptions other) { + connectionReleaseDelay = other.connectionReleaseDelay; maxSize = other.maxSize; maxWaitQueueSize = other.maxWaitQueueSize; } + /** + * Set the delay in milliseconds before idle connections are closed + * + * @param connectionReleaseDelay waiting time in milliseconds + * @return a reference to this, so the API can be used fluently + */ + public PoolOptions setConnectionReleaseDelay(int connectionReleaseDelay) { + this.connectionReleaseDelay = connectionReleaseDelay; + return this; + } + + /** + * @return connection release delay + */ + public int getConnectionReleaseDelay() { + return connectionReleaseDelay; + } + /** * @return the maximum pool size */ diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/ConnectionPool.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/ConnectionPool.java index 261dc8bc..912799b3 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/ConnectionPool.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/ConnectionPool.java @@ -47,23 +47,25 @@ public class ConnectionPool { private final Set all = new HashSet<>(); private final ArrayDeque available = new ArrayDeque<>(); private int size; + private final int connectionReleaseDelay; private final int maxWaitQueueSize; private boolean checkInProgress; private boolean closed; public ConnectionPool(ConnectionFactory connector, int maxSize) { - this(connector, maxSize, PoolOptions.DEFAULT_MAX_WAIT_QUEUE_SIZE); + this(connector, maxSize, PoolOptions.DEFAULT_MAX_WAIT_QUEUE_SIZE, PoolOptions.DEFAULT_CONNECTION_RELEASE_DELAY); } - public ConnectionPool(ConnectionFactory connector, int maxSize, int maxWaitQueueSize) { - this(connector, null, maxSize, maxWaitQueueSize); + public ConnectionPool(ConnectionFactory connector, int maxSize, int maxWaitQueueSize, int connectionReleaseDelay) { + this(connector, null, maxSize, maxWaitQueueSize, connectionReleaseDelay); } - public ConnectionPool(ConnectionFactory connector, Context context, int maxSize, int maxWaitQueueSize) { + public ConnectionPool(ConnectionFactory connector, Context context, int maxSize, int maxWaitQueueSize, int connectionReleaseDelay) { Objects.requireNonNull(connector, "No null connector"); if (maxSize < 1) { throw new IllegalArgumentException("Pool max size must be > 0"); } + this.connectionReleaseDelay = connectionReleaseDelay; this.maxSize = maxSize; this.context = (ContextInternal) context; this.maxWaitQueueSize = maxWaitQueueSize; @@ -105,6 +107,11 @@ public class ConnectionPool { throw new IllegalStateException("Connection pool already closed"); } closed = true; + for (PooledConnection pooled : available) { + if (context != null && connectionReleaseDelay != -1) { + context.owner().cancelTimer(pooled.timerId); + } + } for (PooledConnection pooled : new ArrayList<>(all)) { pooled.close(); } @@ -121,6 +128,7 @@ public class ConnectionPool { private final Connection conn; private Holder holder; + private Long timerId; PooledConnection(Connection conn) { this.conn = conn; @@ -209,6 +217,12 @@ public class ConnectionPool { private void release(PooledConnection proxy) { if (all.contains(proxy)) { available.add(proxy); + if (context != null && connectionReleaseDelay != -1) { + proxy.timerId = context.owner().setTimer(connectionReleaseDelay, x -> { + available.remove(proxy); + all.remove(proxy); + }); + } check(); } } @@ -223,6 +237,9 @@ public class ConnectionPool { while (waiters.size() > 0) { if (available.size() > 0) { PooledConnection proxy = available.poll(); + if (context != null && connectionReleaseDelay != -1) { + context.owner().cancelTimer(proxy.timerId); + } Handler> waiter = waiters.poll(); waiter.handle(Future.succeededFuture(proxy)); } else { diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/impl/pool/ConnectionPoolTest.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/impl/pool/ConnectionPoolTest.java index ba355c69..f1cb1cfc 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/impl/pool/ConnectionPoolTest.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/impl/pool/ConnectionPoolTest.java @@ -204,7 +204,7 @@ public class ConnectionPoolTest { @Test public void testMaxQueueSize1() { ConnectionQueue queue = new ConnectionQueue(); - ConnectionPool pool = new ConnectionPool(queue, 1, 0); + ConnectionPool pool = new ConnectionPool(queue, 1, 0, 60000); SimpleHolder holder1 = new SimpleHolder(); pool.acquire(holder1); SimpleConnection conn = new SimpleConnection(); @@ -230,7 +230,7 @@ public class ConnectionPoolTest { assertFalse(holder2.isComplete()); return promise.future(); } - }, 1, 0); + }, 1, 0, 60000); poolRef[0] = pool; SimpleHolder holder1 = new SimpleHolder(); pool.acquire(holder1); @@ -241,7 +241,7 @@ public class ConnectionPoolTest { @Test public void testConnectionFailure() { ConnectionQueue queue = new ConnectionQueue(); - ConnectionPool pool = new ConnectionPool(queue, 1, 0); + ConnectionPool pool = new ConnectionPool(queue, 1, 0, 60000); SimpleHolder holder1 = new SimpleHolder(); pool.acquire(holder1); Exception cause = new Exception(); @@ -262,9 +262,10 @@ public class ConnectionPoolTest { @Test public void testAcquireOnlyConnectOnce() { ConnectionQueue queue = new ConnectionQueue(); - ConnectionPool pool = new ConnectionPool(queue, 10, 0); + ConnectionPool pool = new ConnectionPool(queue, 10, 0, 60000); SimpleHolder holder1 = new SimpleHolder(); pool.acquire(holder1); assertEquals(1, queue.size()); } + }