Skip to content

Fix leak detection wrongly closing actively-in-use connections during…#149

Merged
rob-bygrave merged 1 commit into
mainfrom
feature/fix-close-busy-bug
Jun 12, 2026
Merged

Fix leak detection wrongly closing actively-in-use connections during…#149
rob-bygrave merged 1 commit into
mainfrom
feature/fix-close-busy-bug

Conversation

@rob-bygrave

Copy link
Copy Markdown
Collaborator

… pool reset

Problem

In production we saw this warning on a read-only pool:

Connection [name[...] startTime[...] busySeconds[0] createdBy[null] stmt[select ...]] not found in BusyList?

busySeconds[0] shows the connection had just been checked out — it was not a leak, yet it had already been removed from the busy list.

Root cause

BusyConnectionBuffer.closeBusyConnections(leakTimeMinutes) decided whether a busy connection was a leak using lastUsedTime() — the time the connection was last returned to the pool (intended for trimming idle/free connections). The correct field is startUseTime() (the time the connection was checked out for its current use), which is even documented as "Used to detect busy connections that could be leaks" but was unused.

As a result, when reset() runs (read-only failover or a DB up/down heartbeat event), a connection that had sat idle in the free list longer than leakTimeMinutes and was then freshly checked out would be misidentified as a leak and force-closed mid-query. When the owning thread finished and called close(), its busy slot was already gone → "not found in BusyList?".

Fix

  • closeBusyConnections now uses startUseTime() (continuous checkout duration) instead of lastUsedTime(). Connections in genuine active use are left to be closed normally when returned, as the reset() Javadoc already intends.
  • Made PooledConnection.startUseTime() package-private.
  • Removed a stray System.out.println left in closeBusyConnection.
  • Moved the test-only pool == null guard above a TRACE log that dereferenced a null pstmtCache.

Tests

Added BusyConnectionBufferTest.closeBusyConnections_onlyClosesLeaks_notActiveConnections, which fails on the old behaviour and passes with the fix. Full module suite green (62 passed).

… pool reset

Problem

In production we saw this warning on a read-only pool:

 Connection [name[...] startTime[...] busySeconds[0] createdBy[null] stmt[select ...]] not found in BusyList?

busySeconds[0] shows the connection had just been checked out — it was not a leak, yet it had already been removed from the busy list.

Root cause

BusyConnectionBuffer.closeBusyConnections(leakTimeMinutes) decided whether a busy connection was a leak using lastUsedTime() — the time the connection was last returned to the pool (intended for trimming idle/free connections). The correct field is startUseTime() (the time the connection was checked out for its current use), which is even documented as "Used to detect busy connections that could be leaks" but was unused.

As a result, when reset() runs (read-only failover or a DB up/down heartbeat event), a connection that had sat idle in the free list longer than leakTimeMinutes and was then freshly checked out would be misidentified as a leak and force-closed mid-query. When the owning thread finished and called close(), its busy slot was already gone → "not found in BusyList?".

Fix

 - closeBusyConnections now uses startUseTime() (continuous checkout duration) instead of lastUsedTime(). Connections in genuine active use are left to be closed normally when returned, as the reset() Javadoc already intends.
 - Made PooledConnection.startUseTime() package-private.
 - Removed a stray System.out.println left in closeBusyConnection.
 - Moved the test-only pool == null guard above a TRACE log that dereferenced a null pstmtCache.

Tests

Added BusyConnectionBufferTest.closeBusyConnections_onlyClosesLeaks_notActiveConnections, which fails on the old behaviour and passes with the fix. Full module suite green (62 passed).
@rob-bygrave rob-bygrave merged commit 69da13a into main Jun 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant