-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add minSize to pool to maintain a minimum # of connections #1319
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,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<Context, Future<SqlConnection>> connectionProvider, | ||
|
@@ -63,10 +64,17 @@ public SqlConnectionPool(Function<Context, Future<SqlConnection>> 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"); | ||
} | ||
|
@@ -78,6 +86,7 @@ public SqlConnectionPool(Function<Context, Future<SqlConnection>> connectionProv | |
this.pipelined = pipelined; | ||
this.idleTimeout = idleTimeout; | ||
this.maxLifetime = maxLifetime; | ||
this.minSize = minSize; | ||
this.maxSize = maxSize; | ||
this.hook = hook; | ||
this.connectionProvider = connectionProvider; | ||
|
@@ -145,18 +154,32 @@ public int size() { | |
return pool.size(); | ||
} | ||
|
||
public void evict() { | ||
public void checkInvariants(long connectionTimeout) { | ||
long now = System.currentTimeMillis(); | ||
pool.evict(conn -> conn.shouldEvict(now), ar -> { | ||
if (ar.succeeded()) { | ||
List<PooledConnection> res = ar.result(); | ||
for (PooledConnection conn : res) { | ||
conn.close(Promise.promise()); | ||
} | ||
checkMin(connectionTimeout); | ||
} | ||
}); | ||
} | ||
|
||
public void checkMin(long connectionTimeout) { | ||
if (pool.size() < minSize) { | ||
ContextInternal context = vertx.getOrCreateContext(); | ||
for (int i = 0; i < minSize; ++i) { | ||
acquire(context, connectionTimeout, (ar) -> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if there should be a flavor of If the @tsegismont is this a valid concern? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Over time (e.g a period of 10 - 30 seconds) this brings up the required number of connections and keeps it there. Even though I currently don't see this behavior your example and concern may be valid. There is a simpler fix though, just pass the required minimum to the evict function; it can easily stop the eviction test when the minimum would be breached. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This requires a change to vert.x core. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the PR with a simpler fix. Instead of calculating a needed value, it now checks if the pool is "low" and acquires This seems to work pretty well and ensures that In practice this "downside" doesn't appear that often. Remember that to trigger the acquisition of connections the pool has to be in some kind of "idle" state because connections are idling and falling below the pool minimum. Worst case a few extra connections are activated for a short period of before idling away. In the end the implementation is somewhere between a One thing to remember when discussing this is that the pool does wait a beat to see if a connection becomes available; it doesn't immediately start a connection when an acquisition request cannot be immediately fulfilled. Looking back to your scenario of current pool size of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I think this should work for most cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because of the asynchronous nature of |
||
if (ar.succeeded()) { | ||
ar.result().cleanup(Promise.promise()); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
public <R> Future<R> execute(ContextInternal context, CommandBase<R> cmd) { | ||
Promise<Lease<PooledConnection>> p = context.promise(); | ||
pool.acquire(context, 0, p); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the issue here is that we might create connections with a context that is not best for the application and force context switching
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume you're referring to
vertx.getOrCreateContext()
. How would you solve this? Pass in a context?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @tsegismont @vietj, any comments?