[ 
https://issues.apache.org/jira/browse/DBCP-599?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17895145#comment-17895145
 ] 

Phil Steitz commented on DBCP-599:
----------------------------------

I may be missing something, but I think the code is working as intended, but 
the driver is not at the required level.  Versions 2.5+ of DBCP require JDBC 
4.2+  Drivers at this level have the method that is missing from your driver.  
The JDBC4 bridge thing should actually probably be removed at this point.   As 
a workaround, you could revert to DBCP 2.8.0 but it would be better to upgrade 
to a compliant driver.

To "fix" this in DBCP, we could catch the AbstractMethodError and fall back to 
close, but I am thinking it might actually be better to just do what we say we 
have been doing for 4+ years now, which is to require 4.2+ and drop the bridge.

> destroyObject method behaves incorrectly on ABANDONED connection, issue with 
> unhandled AbstractMethodError
> ----------------------------------------------------------------------------------------------------------
>
>                 Key: DBCP-599
>                 URL: https://issues.apache.org/jira/browse/DBCP-599
>             Project: Commons DBCP
>          Issue Type: Bug
>    Affects Versions: 2.12.0
>         Environment: Linux, Tomcat 9.0.82, openjdk 17, jconn4.jar (Sybase 
> JDBC 4.0 spec DB driver) in tomcat's lib dir
>            Reporter: denixx baykin
>            Priority: Major
>         Attachments: TestPoolableConnectionFactory.java, 
> abandoned_objects_1.txt, abandoned_objects_other_1.txt, 
> abandoned_objects_query_1.txt, abandoned_traces_1.txt, 
> errors_getting_connection_traces_1_filtered_1.txt, 
> errors_getting_connection_traces_2_filtered_1.txt, part_of_server_xml.txt, 
> part_of_stacktrace_1.txt, testcase_PoolableConnectionFactory_1.patch
>
>
> Short description of the problem:
> The PoolableConnectionFactory.destroyObject method is called for a connection 
> in ABANDONED status, which results in an AbstractMethodError on a real 
> connection due to not calling DelegatingConnection#abort, which takes into 
> account throwing such an error due to Jdbc41Bridge#abort.
> Details:
> It all started when we determined from the application logs in tomcat 9.0.82 
> that stacktraces were being dumped for allegedly not being able to get a new 
> connection from the connect pool.
> At the same time, I know and I am sure that we are configured to handle 
> Abandoned connections and remove them from the pool.
> However, on that day we received an application that after some time started 
> to “complain” that it can't give new connections and that the pool doesn't 
> give these new connections for 20 seconds.
> Stacktrace-dump and heapdump were obtained, and after restarting the 
> application “everything was normalized”.
> After parsing the contents of the heapdump I found out that with maxTotal 
> equal to 20 connections we had 18 connections in ABANDONED state, and only 2 
> in IDLE state, which on that day continued to hold all the load that fell 
> only on them, and, apparently, “when the application needed 3 connections at 
> once in a row” - we had problems with getting them from the pool, why we saw 
> a lot of stacktraces about the impossibility to get these connections from 
> the pool.
> On that day, apparently, a stored procedure was changed, the call of which 
> under certain conditions caused the connection to “freeze”, waiting for a 
> response from the database, and of course it was killed by the pool and 
> transferred to the ABANDONED status.
> We counted 18 such connections in the heapdump, but the most interesting 
> thing is that the configuration for the Abandoned mechanism is set up in such 
> a way that we assumed that such connections would be thrown out of the 
> connection pool and their place would be taken by “fresh” ones, but it was 
> obviously not so.
> As a result, what was the situation: when calling 
> BasicDataSource.getConnection on stacktrace, our application reached the 
> method PoolableConnectionFactory.destroyObject, which resulted in 
> AbstractMethodError, which, due to the fact that it is Error, was not 
> captured by catch-blocks, and knocked out the connection obtaining from the 
> pool, because of which we had a few 500 errors at times when more than 2 
> connections were required at the same time (this is my assumption at the 
> moment).
> I “looked through” the sources of Tomcat 9.0.82 in terms of working with 
> dbcp2, stacktrace frames, and in many of the errors we received at that time, 
> associated with getting a connection from the pool involved method 
> org.apache.commons.dbcp2.PoolableConnectionFactory#destroyObject(org.apache.commons.pool2.PooledObject<org.apache.commons.dbcp2.PoolableConnection>,
>  org.apache.commons.pool2.DestroyMode), designated by Gary Gregory as '@since 
> 2.9.0'.
> This method itself is recorded in the history of git as having appeared in 
> such a commit:
> cbf77a08b7c64c1df3e2b2d2ee5e1415c9a885a1    Mon Dec 28 18:17:43 CET 2020    
> Phil Steitz*    Use abort rather than close to destroy abandoned connections. 
> Fixes DBCP-567. (#68)
> [https://issues.apache.org/jira/projects/DBCP/issues/DBCP-567]
> Its current implementation results in the line 
> org/apache/commons/dbcp2/PoolableConnectionFactory.java:152 where we have 
> p.getObject().getInnermostDelegate().abort(Runnable::run), but 
> getInnermostDelegate does retrieve the “last” connection, which is at the end 
> of the nesting chain, rather than PoolableConnection, which inherits from the 
> DelegatingConnection class and implements the method 
> org.apache.commons.dbcp2.DelegatingConnection#abort , which takes into 
> account that a database driver may be used that supports the JDBC 4.0 
> specification, and there is no abort method implementation there. The 
> org.apache.commons.dbcp2.Jdbc41Bridge#abort method provides "workaround" in 
> this case, ensuring that close is called instead of abort when the JVM throws 
> an AbstractMethodError.
> In fact, we have in our application with a tomcat that supports the JDBC 4.2 
> specification, a driver that is implemented according to the JDBC 4.0 
> specification, and it is this nuance that made DBCP2 unable to cope with pool 
> cleanup when the removeAbandonedOnBorrow="true" parameter is specified in the 
> pool settings. The only thing I don't understand yet is why the pool didn't 
> perform OnMaintenance cleanup with the specified parameters 
> removeAbandonedTimeout="600" removeAbandonedOnMaintenance="true" 
> logAbandoned="true" minEvictableIdleTimeMillis="30000". Is this a settings 
> for some internal sheduler?
> To reinforce all of the above, I attach the files:
> testcase_PoolableConnectionFactory_1.patch - a testcase for 
> PoolableConnectionFactory.destroyObject, which enlightens the problem.
> TestPoolableConnectionFactory.java - the same file, but in form of the java 
> source file.
> part_of_stacktrace_1.txt - the most important file of all, it contains the 
> part of the stacktrace that is repeated in all connection acquisition errors.
> abandoned_traces_1.txt - all (anonymized) stacktraces from catalina.out, 
> which are related to connection rejection in the database when the response 
> time is exceeded, and transfer to ABANDONED status.
> errors_getting_connection_traces_2_filtered_1.txt - All (anonymized) errors 
> that include Caused by: java.lang.AbstractMethodError: Method 
> com/sybase/jdbc4/jdbc/SybConnection.abort(Ljava/util/concurrent/Executor;)V 
> is abstract.
> errors_getting_connection_traces_1_filtered_1.txt - All (anonymized) errors 
> where we tried to get a new connection from the pool and didn't wait the item.
> part_of_server_xml.txt - (Anonymized) Resources from the conf/server.xml file.
> abandoned_objects_1.txt - List of 18 DefaultPooledObject that appeared in the 
> pool in ABANDONED status in heapdump, and “did not want to be destroyed”.
> abandoned_objects_other_1.txt - Several other connections, from other pools, 
> and 2 connections from the same pool that were involved in the “problem”, in 
> IDLE status, which seem to be holding the load.
> abandoned_objects_query_1.txt - queries for VisualVM , OQL Console tab, which 
> retrieved the previous 2 files.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to