Issue Details (XML | Word | Printable)

Key: DERBY-2142
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Kathey Marsden
Reporter: Asif H. Shahid
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Derby

NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario

Created: 04/Dec/06 10:54 AM   Updated: 01/Feb/08 07:59 PM
Return to search
Component/s: JDBC
Affects Version/s: 10.0.2.0, 10.0.2.1, 10.1.1.0, 10.1.2.1, 10.1.3.1, 10.2.1.6
Fix Version/s: 10.1.3.2, 10.2.2.1, 10.3.3.0, 10.4.1.3

Time Tracking:
Not Specified

File Attachments:
  Size
Text File Licensed for inclusion in ASF works derby-2142_diff.txt 2008-01-26 12:39 AM Kathey Marsden 0.6 kB
Text File Licensed for inclusion in ASF works derby-2142_diff2.txt 2008-01-28 10:04 PM Kathey Marsden 2 kB
Text File Licensed for inclusion in ASF works derby-2142_diff3.txt 2008-01-28 11:19 PM Kathey Marsden 2 kB
Text File Licensed for inclusion in ASF works derby-2142_stat.txt 2008-01-26 12:39 AM Kathey Marsden 0.1 kB
Environment: The issue can appear in any environment as the bug is in the source code . The bug has been verified in Suse Linux env.
Issue Links:
Reference
 

Urgency: Normal
Resolution Date: 01/Feb/08 07:59 PM


 Description  « Hide
We are using the Derby's Transactional DataSource class ( org.apache.derby.jdbc.EmbeddedXADataSource ) to create a pool of XAConnections in our application.
Whenever a thread in a JTA transaction requests for a SQLConnection , we retrieve an XAConnection from the pool. From the XAConnection , we register the XAResource with the TransactionManager & return a java.sql.Connection to the application.
A class implementing the ConnectionEventListener is registered with the XAConnection to get callback connectionClosed ( ) when the thead closes the java.sql.Connection. In this callback, we invoke XAResource.end & return the XAConnection to our pool so that other threads can use it.

We have encountered NullPointerException , when performing operation on java.sql.Connection.
The stacktrace is as follows
at
org.apache.derby.jdbc.XAStatementControl.<init>(XAStatementControl.java:71)
   at
org.apache.derby.jdbc.EmbedXAConnection.wrapStatement(EmbedXAConnection.java:162)
   at
org.apache.derby.iapi.jdbc.BrokeredConnection.createStatement(Unknown
Source)
   at
com.gemstone.gemfire.internal.datasource.ConnectionPoolingTest$1.run(ConnectionPoolingTest.java:174)
   at java.lang.Thread.run(Thread.java:595)


I have done some debugging on source code of db-derby-10.2.1.6-src & have following explanation of the bug & a suggested fix. However, I want to confirm that it is genuinely a bug & not a problem in our understanding of the Datasource spec behaviour.

Reason for the bug:-

The class EmbedPooledConnection.java stores in the field currentConnectionHandle ( of class BrokeredConnection) a reference of the java.sql.Connection object , being returned to the application,
Now ,whenever the client closes the java.sql.Connection , the code flow is

EmbedPooledConnection.close() --> EmbedPooledConnection.notifyClose().
In the function EmbedPooledConnection.notifyClose(), it notifies my listener ( javax.sql.ConnectionEventListener) ) where I return the XAConnection to the pool ( after deregistering the XAResource).
The last line of EmbedPooledConnection.close() makes the currentConnectionHandle field as null.

The issue here is that javax.sql.ConnectionEventListener.connectionClosed is invoked before making the currentConenctionHandle field as null. Thus XAConnection is returned to the pool , ready for pickup by a new thread. This new thread obtains a java.sql.Connection whose reference gets assigned to the currentConnectionHandle field, meanwhile the previous thread completes the EmbedPooledConnection.close making the newly assigned currentConnectionHandle as null.

Thus a previous thread's close makes a field null of an XAConnection, which has been assigned to a new thread.
The bug is easily reproducible in a multi threaded scenario ( 20 threads or so) with a pool size of around 4 XAConnections so that there is heavy contention on XAConnection.

The fix is to rearrange the code of EmbedPooledConenction.java 's closingConnection () as

bug :
public boolean closingConnection() {
     notifyClose();
     currentConnectionHandle = null;
    return false;

}

bug fix :
public boolean closingConnection() {
     currentConnectionHandle = null;
     notifyClose();
     return false;
}










 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Daniel John Debrunner added a comment - 11/Dec/06 09:22 PM
Thanks Asif for the suggested change and detailed analysis. I think you are correct in that it would make sense to re-order the code as you have shown, though possibly some investigation should be made to see if clearing currentConnectionHandle before notifyClose() breaks any assumptions during the notification of the close. Since the listeners can get a handed to the PooledConnection or XAConnection & XAResource we would just have to ensure that any method they can call on those interfaces behaves correctly.

I also think in addition synchronization should be added, probably by making closingConnection() a synchronized method.

Rick Hillegas added a comment - 12/Dec/06 10:13 PM
Adjusting urgency and priority to the standard levels.

Rick Hillegas made changes - 12/Dec/06 10:13 PM
Field Original Value New Value
Urgency Urgent Normal
Priority Critical [ 2 ] Major [ 3 ]
Kathey Marsden added a comment - 16/Jan/08 11:06 PM
Asif, do you have a reproduction for this issue?

Kathey Marsden made changes - 25/Jan/08 10:21 PM
Assignee Kathey Marsden [ kmarsden ]
Kathey Marsden added a comment - 26/Jan/08 12:39 AM
Attached is patch for this issue with Asif's suggetion. (Thank you Asif.) plus making closingConnection synchronized as Dan suggested. I am still kind of fuzzy on what I have to check to make sure PooledConnection, XAConnection and XAResource methods behave correctly, but am trying to figure that out. Any tips would be greatly appreciated. suites.All passed, running derbyall now.

Kathey Marsden made changes - 26/Jan/08 12:39 AM
Attachment derby-2142_stat.txt [ 12374107 ]
Attachment derby-2142_diff.txt [ 12374106 ]
Mamta A. Satoor added a comment - 28/Jan/08 06:39 PM
The ConnectionEventListner javadoc for connectionClosed says
          Notifies this ConnectionEventListener that the application has called the method close on its representation of a pooled connection.

It does not say whether the notification has been sent after the pooled connection is marked closed or before the pooled connection will be marked closed so it seems like it will be ok for us to mark currentConnectionHandle as null and then send the notifications.

Daniel John Debrunner added a comment - 28/Jan/08 08:08 PM
Section 11.2 & 12.5 of JDBC 4 specification indicate that the connection can be returned to the pool when the ConnectionEventListener.connectionClosed() is called, so the pooled connection must be (as Asif suggested) set into the correct state before the callback is made.

Daniel John Debrunner added a comment - 28/Jan/08 08:18 PM
There's some potential for minor cleanup here - notifyClose() is synchronized and only ever called from closingConnection.
So with the current patch the synchronization will be obtained twice. Merging the two methods into one would avoid this and the indication that notifyClose() can be called from other code.

Kathey Marsden added a comment - 28/Jan/08 08:18 PM
Thanks Dan and Mamta for the input. Dan could you elaborate on your comment:
"Since the listeners can get a handed to the PooledConnection or XAConnection & XAResource we would just have to ensure that any method they can call on those interfaces behaves correctly."

What exactly do I need to be checking?


Daniel John Debrunner added a comment - 28/Jan/08 08:27 PM
>> "Since the listeners can get a handed to the PooledConnection or XAConnection & XAResource we would just have to ensure that any method they can call on those interfaces behaves correctly."
> What exactly do I need to be checking?

Nothing. :-)

It's covered by my recent comment which probably was posted while you were writing yours.

Sections 11.2 and 12.5 state that at the time of the callback they can return the PooledConnection to the pool for re-use, thus at time of the callback the PooledConnection must be disassociated from its previous logical connection. Note the logical connection is being closed, not the pooled connection.

The buggy code passes the PooledConnection to the callbacks in a state where it is still associated to the just closed logical connection, my original concern was what is the expected state of the PooledConnection for the listeners: still associated or disassociated. I hadn't researched the details then.

Kathey Marsden added a comment - 28/Jan/08 10:04 PM
Attached is a revised patch rolling notifyClose into closingConnection().derby-2142_diff2.txt

Kathey Marsden made changes - 28/Jan/08 10:04 PM
Attachment derby-2142_diff2.txt [ 12374222 ]
Daniel John Debrunner added a comment - 28/Jan/08 10:32 PM
Patch 2 seems to have lost the synchronization on the closingConnection() method.

---------------

This comment here is lacking the "why", it's really just describing the code so it's not adding any value.
Why it needs to be before is the important information here.

+ //DERBY-2142 - Null out the connection handle BEFORE notifying listeners.
  currentConnectionHandle = null;




Kathey Marsden added a comment - 28/Jan/08 11:19 PM
Thanks Dan for catching that! I was reeditting with emacs to get the white space right and botched the change #:(

I sure would feel better if I had a repro for this.
running tests now on derby-2142_diff3.txt

Kathey Marsden made changes - 28/Jan/08 11:19 PM
Attachment derby-2142_diff3.txt [ 12374227 ]
Repository Revision Date User Message
ASF #616141 Tue Jan 29 02:26:01 UTC 2008 kmarsden DERBY-2142 NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario

core fix contributed by Asif Shahid with further suggestions from Dan Debrunner
Files Changed
MODIFY /db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java

Daniel John Debrunner added a comment - 29/Jan/08 06:06 AM
I added a test fixture DataSourceTest.testPooledReuseOnClose that covers this bug. Failed before revision 616141 and passes now on embedded.

It fails for network client, I didn't investigate that, just didn't run the test in that environment. Either a new bug should be added or it should be fixed under this bug.

It would be good if you could make this code comment have value (see earlier issue comment):

+ //DERBY-2142 - Null out the connection handle BEFORE notifying listeners.

adding the why might help ensure the code doesn't get re-ordered in the future and explain it for anyone reading the code.


Repository Revision Date User Message
ASF #616177 Tue Jan 29 06:06:30 UTC 2008 djd DERBY-2142 (test) Add a fixture (testPooledReuseOnClose) to DataSourceTest that tests the fix to DERBY-2142. It failed before revision 616141 and passed after for embedded, but fails for network client so it is disabled for that env.
Files Changed
MODIFY /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java

Kristian Waagan added a comment - 29/Jan/08 11:16 AM
Thanks for adding the test fixture Dan.

I think the client driver might have the same problem as the embedded driver. I'm currently working in that area of the code, and I'll investigate it.
If required, I'd like to attach a patch to this issue.

Kathey Marsden added a comment - 29/Jan/08 08:45 PM
Hi Dan,

Thanks for the fixture. Here is the revised comment, gleaned from the comments in this issue and my understanding of it.


//DERBY-2142-Null out the connection handle BEFORE notifying listeners.
//At time of the callback the PooledConnection must be
//disassociated from its previous logical connection.
//If not, there is a risk that the Pooled
//Connection could be returned to the pool, ready for pickup by a
//new thread. This new thread then might obtain a java.sql.Connection
//whose reference might get assigned to the currentConnectionHandle
//field, meanwhile the previous thread completes the close making
//the newly assigned currentConnectionHandle null, resulting in an NPE.



Repository Revision Date User Message
ASF #616575 Wed Jan 30 01:12:01 UTC 2008 kmarsden DERBY-2142 NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario

Update code comments.
Files Changed
MODIFY /db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java

Repository Revision Date User Message
ASF #616880 Wed Jan 30 20:01:32 UTC 2008 kmarsden DERBY-2142 NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario

port from trunk revision 616141, 616177, 616575
Files Changed
MODIFY /db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/junit/JDBCDataSource.java
MODIFY /db/derby/code/branches/10.3/java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java
MODIFY /db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java

Repository Revision Date User Message
ASF #616966 Thu Jan 31 00:24:10 UTC 2008 kmarsden DERBY-2142 NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario
port from trunk, revisions 616141,616575
Files Changed
MODIFY /db/derby/code/branches/10.2/java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java

Repository Revision Date User Message
ASF #617145 Thu Jan 31 15:05:29 UTC 2008 kmarsden DERBY-2142 NullPointerException while using XAConnection/PooledConnection in a heavily contended multithreaded scenario

port from trunk revision 616141, 616575
Files Changed
MODIFY /db/derby/code/branches/10.1/java/engine/org/apache/derby/jdbc/EmbedPooledConnection.java

Kathey Marsden added a comment - 31/Jan/08 05:02 PM
I ported the embedded fix to 10.3, 10.2 and 10.1. If the client fix won't be going to all those branches, it might make sense to make a new issue for that.

Kathey Marsden made changes - 01/Feb/08 07:57 PM
Link This issue relates to DERBY-3379 [ DERBY-3379 ]
Kathey Marsden added a comment - 01/Feb/08 07:59 PM
Resolving this issue for embedded. Opened DERBY-3379 for client.

Kathey Marsden made changes - 01/Feb/08 07:59 PM
Resolution Fixed [ 1 ]
Fix Version/s 10.3.2.2 [ 12312885 ]
Fix Version/s 10.2.2.1 [ 12312251 ]
Fix Version/s 10.4.0.0 [ 12312540 ]
Status Open [ 1 ] Resolved [ 5 ]
Fix Version/s 10.1.3.2 [ 12311972 ]
Repository Revision Date User Message
ASF #619695 Fri Feb 08 00:14:12 UTC 2008 djd Expand the DataSourceTest testing added in DERBY-2142 to include closing the PooledConnection during a callback resulting from a close on its logical connection.
Files Changed
MODIFY /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/DataSourceTest.java