Describe the bug
Every borrow from the pool validates the connection it takes out, and Connection.isValid() is a round trip to the database:
// opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/CachedConnection.java:84-97
CachedConnection con = cached.get(connectionString).poll(waitTime, TimeUnit.MILLISECONDS);
while (con != null) {
if (!con.isValid(0)) {
...
} else {
return con;
}
}
Every operation of the backend borrows through this path — JDBCStorage.read(), write(), the cursor of a search, the import. So one LDAP operation costs two exchanges with the database rather than one: the validation, and then the statement the operation actually came for. On PostgreSQL isValid runs an empty query, on MySQL it sends a ping, on Oracle it is a round trip of its own; all of them are a network round trip and a scheduling of the database's own worker.
The check earns its keep on a connection that has been sitting in the pool: the database may have closed it, a firewall may have dropped the flow. It earns nothing on a connection that came back to the pool a millisecond ago, which — with a pool that keeps connections for org.openidentityplatform.opendj.jdbc.ttl (15 s by default) and a backend under load — is most of them.
Impact
A fixed per-operation latency of one database round trip, and a matching amount of work on the database, on every search and every modify. On a database reached over a network rather than over loopback it is the dominant part of the cost of a small operation: the entry read of read() is a single indexed row, and it is paid for twice.
Sibling of the work in #859 / #860 / #863, which were about exactly this kind of per-operation cost in the same backend.
Expected behavior
Skip the validation for a connection returned to the pool recently — the "alive bypass window" of HikariCP (aliveBypassWindowMs, 500 ms by default) is the established shape of this: remember when a connection went back into the pool, and validate only when it has been idle longer than the window. A connection that broke inside the window still surfaces as a failure of the statement itself, which is where a connection breaking mid-operation surfaces anyway.
Worth measuring alongside it: whether the validation is needed at all on the path where the connection is handed straight back out, or whether letting the statement fail and retrying the borrow once is cheaper in aggregate.
Environment
master (5.2.x), all four JDBC dialects. #876 gives this validation the bound it was missing (isValid(0) means "no timeout" in the JDBC contract) but leaves it on every borrow, so the round trip described here is unchanged by it.
Noticed while fixing #872 (PR #876).
Describe the bug
Every borrow from the pool validates the connection it takes out, and
Connection.isValid()is a round trip to the database:Every operation of the backend borrows through this path —
JDBCStorage.read(),write(), the cursor of a search, the import. So one LDAP operation costs two exchanges with the database rather than one: the validation, and then the statement the operation actually came for. On PostgreSQLisValidruns an empty query, on MySQL it sends a ping, on Oracle it is a round trip of its own; all of them are a network round trip and a scheduling of the database's own worker.The check earns its keep on a connection that has been sitting in the pool: the database may have closed it, a firewall may have dropped the flow. It earns nothing on a connection that came back to the pool a millisecond ago, which — with a pool that keeps connections for
org.openidentityplatform.opendj.jdbc.ttl(15 s by default) and a backend under load — is most of them.Impact
A fixed per-operation latency of one database round trip, and a matching amount of work on the database, on every search and every modify. On a database reached over a network rather than over loopback it is the dominant part of the cost of a small operation: the entry read of
read()is a single indexed row, and it is paid for twice.Sibling of the work in #859 / #860 / #863, which were about exactly this kind of per-operation cost in the same backend.
Expected behavior
Skip the validation for a connection returned to the pool recently — the "alive bypass window" of HikariCP (
aliveBypassWindowMs, 500 ms by default) is the established shape of this: remember when a connection went back into the pool, and validate only when it has been idle longer than the window. A connection that broke inside the window still surfaces as a failure of the statement itself, which is where a connection breaking mid-operation surfaces anyway.Worth measuring alongside it: whether the validation is needed at all on the path where the connection is handed straight back out, or whether letting the statement fail and retrying the borrow once is cheaper in aggregate.
Environment
master (5.2.x), all four JDBC dialects. #876 gives this validation the bound it was missing (
isValid(0)means "no timeout" in the JDBC contract) but leaves it on every borrow, so the round trip described here is unchanged by it.Noticed while fixing #872 (PR #876).