Bug 65929 - Connection is not released on Connection.abort() call
Summary: Connection is not released on Connection.abort() call
Status: NEW
Alias: None
Product: Tomcat Modules
Classification: Unclassified
Component: jdbc-pool (show other bugs)
Version: unspecified
Hardware: All All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-03-03 22:33 UTC by Alexey Kutishchev
Modified: 2022-03-03 22:33 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Kutishchev 2022-03-03 22:33:18 UTC
[NOT A CONTRIBUTION]


JDBC Pool Version: 9.0.49
Database: Oracle
JDBC Version:  19.3.0.0
OS: Mac, Linux


The problem I'm running into:
We are using Tomcat JDBC Pool. When getting the network failure between server and database something like 'Connection Reset by Peer' ORM framework we are using  'abort' method from JDBC Connection which goes through the ProxyConnection class. As a result underlying physical connection to DB is closed but PooledConnection is not return to the pool.

The reason to using 'abort' is that oracle PhysicalConnection in case of network failure sometimes goes to the inconsistent state and calling plain 'close' throws an unexpected exception.

Seems like ProxyConnection is missing special handling for the 'abort' method which should call abort on the underlying connection and return PoolConnection to the pool afterwards.

According to JDBC specification link - https://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html#abort-java.util.concurrent.Executor-
calling 'abort' should perform close on the connection.

To reproduce following can be done:
Put a debug point to the code making a SQL query. Find in the call stack the ProxyConnection class and make a call of abort on it. As a result underlying connection is going to be closed by not return to the pool as released.

The easiest way to fix:
Put a handler for the 'abort' method which first abort the underlying connection and when 'close' it with return to the pool. Same as 'close' is handled.

As a workaround we have fixed that using interceptor:

[NOT A CONTRIBUTION]

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object invoke = super.invoke(proxy, method, args);
   if (compare(ABORT_VAL, method) && findProxyConnectionInChain().isPresent()) {
       ProxyConnection proxyConnection = findProxyConnectionInChain().get();
       proxyConnection.getDelegateConnection().setDiscarded(true);
       try {
           super.invoke(proxy, Connection.class.getDeclaredMethod(ProxyConnection.CLOSE_VAL), args);
       } catch (Exception e) {
		  // Error handling
       }

   }
   return invoke;
}

private Optional<ProxyConnection> findProxyConnectionInChain() {
   JdbcInterceptor next  = getNext();

   while (next != null) {
       if (next instanceof ProxyConnection) return  Optional.of((ProxyConnection) next);
       next = next.getNext();
   }

   return Optional.empty();
}