[ https://issues.apache.org/jira/browse/DBCP-484?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16410711#comment-16410711 ]
Zheng Feng commented on DBCP-484: --------------------------------- Hi, I think there might be a race condition when closing the ManagedConnection There are two methods which could call connection.close() and the one is in [ManagedConnection.close()|https://github.com/apache/commons-dbcp/blob/master/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java#L160] and the other is [ManagedConncetion.transactionComplete()|https://github.com/apache/commons-dbcp/blob/master/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java#L188] which is used in calling back when the transaction is completed. {code} public void close() throws SQLException { if (!isClosedInternal()) { try { // Don't actually close the connection if in a transaction. The // connection will be closed by the transactionComplete method. if (transactionContext == null) { super.close(); } } finally { setClosedInternal(true); } } } {code} The thread of close() could be switched after check (transactionContext == null) and before the setCloseInternal(true). So it thinks it is still in a transaction but dose not set the _closed. {code} protected void transactionComplete() { transactionContext = null; // If we were using a shared connection, clear the reference now that // the transaction has completed if (isSharedConnection) { setDelegate(null); isSharedConnection = false; } // If this connection was closed during the transaction and there is // still a delegate present close it final Connection delegate = getDelegateInternal(); if (isClosedInternal() && delegate != null) { try { setDelegate(null); if (!delegate.isClosed()) { delegate.close(); } } catch (final SQLException ignored) { // Not a whole lot we can do here as connection is closed // and this is a transaction callback so there is no // way to report the error. } } } {code} The thread of transationComplete() should check isClosedInternal() which is still false. So it will not close the connection. And the connection.close() is missed both in close() and transactionComplete(). I think it could be one cause of the connection leaking. > Connection leak during XATransaction in high load > ------------------------------------------------- > > Key: DBCP-484 > URL: https://issues.apache.org/jira/browse/DBCP-484 > Project: Commons Dbcp > Issue Type: Bug > Affects Versions: 2.2.0 > Reporter: Emanuel Freitas > Priority: Major > > We're experiencing a connection leak in a distributed transaction when the > system is under heavy load. We're using commons-dbcp (latest version) + > eclipselink and narayana to perform transaction coordination. > From time to time we can see a stacktrace reporting an abandoned connection. > We are trying to figure out what's the root cause and we think that might be > some issue in the commons dbcp (not sure) . More specifically, this parte of > the code: > ManagedConnection#updateTransactionStatus > {code:java} > if (transactionContext != null) { > if (transactionContext.isActive()) { > if (transactionContext != > transactionRegistry.getActiveTransactionContext()) { > throw new SQLException("Connection can not be used while enlisted > in another transaction"); > } > return; > } > // transaction should have been cleared up by TransactionContextListener, > but in > // rare cases another lister could have registered which uses the > connection before > // our listener is called. In that rare case, trigger the transaction > complete call now > transactionComplete(); > }{code} > > If the transactionContext is different than null but the state is not > "active" (ex: STATUS_ROLLEDBACK, STATUS_ROLLING_BACK, etc) it executes the > transactionComplete mothod that clears the reference to a shared connection > and after that the connection is never closed (returned to the pool). > > If we move the transactionComplete(); to an else,(see below), the connection > leak does not happen. > {code:java} > if (transactionContext != null) { > if (transactionContext.isActive()) { > if (transactionContext != > transactionRegistry.getActiveTransactionContext()) { > throw new SQLException("Connection can not be used while enlisted > in another transaction"); > } > return; > } > } else { > transactionComplete(); > }{code} > > After this the dbcp unit tests still pass but I'm not sure about this > changes. Can you please check? > Thanks > -- This message was sent by Atlassian JIRA (v7.6.3#76005)