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 88cda6b73..baf0aa54a 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 @@ -65,6 +65,11 @@ public static void fromJson(Iterable> json, obj.setMaxWaitQueueSize(((Number)member.getValue()).intValue()); } break; + case "minSize": + if (member.getValue() instanceof Number) { + obj.setMinSize(((Number)member.getValue()).intValue()); + } + break; case "name": if (member.getValue() instanceof String) { obj.setName((String)member.getValue()); @@ -104,6 +109,7 @@ public static void toJson(PoolOptions obj, java.util.Map json) { } json.put("maxSize", obj.getMaxSize()); json.put("maxWaitQueueSize", obj.getMaxWaitQueueSize()); + json.put("minSize", obj.getMinSize()); if (obj.getName() != null) { json.put("name", obj.getName()); } 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 0239dae8d..803dcbe95 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 @@ -32,6 +32,11 @@ @DataObject(generateConverter = true) public class PoolOptions { + /** + * The default minimum number of connections a client will keep open in the pool = 2 + */ + public static final int DEFAULT_MIN_SIZE = 0; + /** * The default maximum number of connections a client will pool = 4 */ @@ -92,6 +97,7 @@ public class PoolOptions { */ public static final int DEFAULT_EVENT_LOOP_SIZE = 0; + private int minSize = DEFAULT_MIN_SIZE; private int maxSize = DEFAULT_MAX_SIZE; private int maxWaitQueueSize = DEFAULT_MAX_WAIT_QUEUE_SIZE; private int idleTimeout = DEFAULT_IDLE_TIMEOUT; @@ -113,6 +119,7 @@ public PoolOptions(JsonObject json) { } public PoolOptions(PoolOptions other) { + minSize = other.minSize; maxSize = other.maxSize; maxWaitQueueSize = other.maxWaitQueueSize; idleTimeout = other.idleTimeout; @@ -122,6 +129,30 @@ public PoolOptions(PoolOptions other) { eventLoopSize = other.eventLoopSize; } + /** + * @return the minimum pool size + */ + public int getMinSize() { + return minSize; + } + + /** + * Set the minimum pool size + * + * @param minSize the minimum pool size + * @return a reference to this, so the API can be used fluently + */ + public PoolOptions setMinSize(int minSize) { + if (minSize < 0) { + throw new IllegalArgumentException("Min size cannot be negative"); + } + if (minSize > maxSize) { + throw new IllegalArgumentException("Min size cannot be greater than max size"); + } + this.minSize = minSize; + return this; + } + /** * @return the maximum pool size */ diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/PoolImpl.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/PoolImpl.java index 7b28da062..a02dc3f5e 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/PoolImpl.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/PoolImpl.java @@ -68,7 +68,9 @@ public PoolImpl(VertxInternal vertx, this.timerID = -1L; this.pipelined = pipelined; this.vertx = vertx; - this.pool = new SqlConnectionPool(ctx -> connectionProvider.apply(ctx), () -> connectionInitializer, afterAcquire, beforeRecycle, vertx, idleTimeout, maxLifetime, poolOptions.getMaxSize(), pipelined, poolOptions.getMaxWaitQueueSize(), poolOptions.getEventLoopSize()); + this.pool = new SqlConnectionPool(ctx -> connectionProvider.apply(ctx), () -> connectionInitializer, + afterAcquire, beforeRecycle, vertx, idleTimeout, maxLifetime, poolOptions.getMinSize(), poolOptions.getMaxSize(), + pipelined, poolOptions.getMaxWaitQueueSize(), poolOptions.getEventLoopSize()); this.closeFuture = closeFuture; } @@ -81,6 +83,7 @@ public Pool init() { }); } } + pool.startMin(connectionTimeout); return this; } @@ -102,7 +105,7 @@ private void runEviction() { runEviction(); }); } - pool.evict(); + pool.evict(connectionTimeout); } @Override diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/SqlConnectionPool.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/SqlConnectionPool.java index f8f3d8690..1a94a01fd 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/SqlConnectionPool.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/pool/SqlConnectionPool.java @@ -36,6 +36,8 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import static java.lang.Math.max; + /** * Todo : * @@ -54,6 +56,7 @@ public class SqlConnectionPool { private final boolean pipelined; private final long idleTimeout; private final long maxLifetime; + private final int minSize; private final int maxSize; public SqlConnectionPool(Function> connectionProvider, @@ -63,10 +66,17 @@ public SqlConnectionPool(Function> connectionProv VertxInternal vertx, long idleTimeout, long maxLifetime, + int minSize, int maxSize, boolean pipelined, int maxWaitQueueSize, int eventLoopSize) { + if (minSize < 0) { + throw new IllegalArgumentException("Pool min size must be > 0"); + } + if (minSize > maxSize) { + throw new IllegalArgumentException("Pool min size must be <= max size"); + } if (maxSize < 1) { throw new IllegalArgumentException("Pool max size must be > 0"); } @@ -76,8 +86,9 @@ public SqlConnectionPool(Function> connectionProv this.pool = ConnectionPool.pool(connector, new int[]{maxSize}, maxWaitQueueSize); this.vertx = vertx; this.pipelined = pipelined; - this.idleTimeout = idleTimeout; - this.maxLifetime = maxLifetime; + this.idleTimeout = idleTimeout > 0 ? idleTimeout : Long.MAX_VALUE; + this.maxLifetime = maxLifetime > 0 ? maxLifetime : Long.MAX_VALUE; + this.minSize = minSize; this.maxSize = maxSize; this.hook = hook; this.connectionProvider = connectionProvider; @@ -145,7 +156,7 @@ public int size() { return pool.size(); } - public void evict() { + public void evict(long connectionTimeout) { long now = System.currentTimeMillis(); pool.evict(conn -> conn.shouldEvict(now), ar -> { if (ar.succeeded()) { @@ -153,10 +164,25 @@ public void evict() { for (PooledConnection conn : res) { conn.close(Promise.promise()); } + startMin(connectionTimeout); } }); } + public void startMin(long connectionTimeout) { + int needed = max(minSize - pool.size(), 0); + if (needed > 0) { + ContextInternal context = vertx.getOrCreateContext(); + for (int i = 0; i < needed; ++i) { + acquire(context, connectionTimeout, (ar) -> { + if (ar.succeeded()) { + ar.result().cleanup(Promise.promise()); + } + }); + } + } + } + public Future execute(ContextInternal context, CommandBase cmd) { Promise> p = context.promise(); pool.acquire(context, 0, p);