On 15/03/2013 21:36, Colin Ingarfield wrote:

Short version:
Your upgrade to the latest Connector/J will have fixed this particular
problem.


Long version:

<snip/>

>>>> Found one Java-level deadlock: =============================

<snip>

Thread 1:

>>>> Here are the stack traces: Thread 12820: (state = BLOCKED) -
>>>> com.mysql.jdbc.ConnectionImpl.getCharacterSetMetadata() @bci=0,
>>>> line=2851 (Compiled frame) -
>>>> com.mysql.jdbc.Field.getStringFromBytes(int, int) @bci=37,
>>>> line=717 (Compiled frame) - com.mysql.jdbc.Field.getName() @bci=17,
>>>> line=631 (Interpreted frame) -
>>>> com.mysql.jdbc.ResultSetImpl.buildIndexMapping() @bci=78, line=752
>>>> (Compiled frame) -
>>>> com.mysql.jdbc.ResultSetImpl.findColumn(java.lang.String) @bci=12,
>>>> line=1110 (Interpreted frame) -
>>>> com.mysql.jdbc.ResultSetImpl.getString(java.lang.String) @bci=3,
>>>> line=5609 (Interpreted frame) -
>>>> org.eclipse.jetty.server.session.JDBCSessionManager$1.run()
>>>> @bci=111, line=844 (Interpreted frame) -

<snip/>

Thread 2:

>>>> Thread 890: (state = BLOCKED) -
>>>> com.mysql.jdbc.ResultSetImpl.realClose(boolean) @bci=0, line=7195
>>>> (Interpreted frame) - com.mysql.jdbc.ResultSetImpl.close() @bci=2,
>>>> line=909 (Interpreted frame) -
>>>> com.mysql.jdbc.StatementImpl.realClose(boolean, boolean) @bci=126,
>>>> line=2478 (Interpreted frame) -
>>>> com.mysql.jdbc.PreparedStatement.realClose(boolean, boolean)
>>>> @bci=71, line=3098 (Interpreted frame) -
>>>> com.mysql.jdbc.ConnectionImpl.closeAllOpenStatements() @bci=90,
>>>> line=1628 (Interpreted frame) -
>>>> com.mysql.jdbc.ConnectionImpl.realClose(boolean, boolean, boolean,
>>>> java.lang.Throwable) @bci=176, line=4388 (Interpreted frame) -
>>>> com.mysql.jdbc.ConnectionImpl.close() @bci=32, line=1601
>>>> (Interpreted frame) -
>>>> org.apache.tomcat.jdbc.pool.PooledConnection.disconnect(boolean)
>>>> @bci=47, line=330 (Interpreted frame) -

<snip/>

>>>> Once I dug up these stack traces I started to wonder if the mysql
>>>> driver was the problem (or contributing to the problem.)  I was
>>>> using Connector/J version 5.1.19 when the deadlock occurred.  I
>>>> found this bug:  http://bugs.mysql.com/bug.php?id=61247 which
>>>> sounds a lot like what appears to have happened.  I'm interested in
>>>> your thoughts on this.

The problem is related to two threads accessing the same connection.
Given the scenario - the pool spots a potentially abandoned connection
and tries to close it - I don't view this as unreasonable behaviour by
the pool since there are no other options available.

The problem is that Thread 1 (above) results in this call order:
ResultSetImpl.findColumn(java.lang.String)  - Syncs on ResultSetImpl
...
ConnectionImpl.getCharacterSetMetadata()    - Syncs on ConnectionImpl

while Thread 2 results in this call order:
ConnectionImpl.close()            - Syncs on ConnectionImpl
...
ResultSetImpl.realClose(boolean)  - Syncs on ResultSetImpl

Two threads obtaining the same locks in a different order will result in
a deadlock.

I'd view that as a bug in the JDBC driver since - to my mind - "thread
safe" includes "doesn't deadlock". However, I can see a counter argument
that goes along the lines of:
- The deadlock is triggered when the cleaner thread tries to close an
active connection
- The cleaner thread is closing abandoned connections
- The only cause of an abandoned connection is buggy client code
- Therefore the real root cause is buggy client code


>>>> In the meantime I have upgraded to latest Connector/J which
>>>> includes a fix for this bug.  I was running the old driver for
>>>> months before this deadlock, though, so it will be difficult to
>>>> know if it fixes the issue or not.

A review of the Connector/J code indicates that this particular deadlock
has been fixed (all the syncs above now sync on a new connectionMutex
object). This a) fixes this particular deadlock and b) ensures that
external code that syncs on a Connection/ResultSet/whatever can't
interfere and trigger a deadlock.

<snip/>

> My database access code is built on Spring 3's JDBC APIs, so I do not
> do any explicit connection management in my code.  Its Spring's job to
> get connections and release them, and I assume its JDBC APIs is
> well-tested.  So I don't think my code is the problem here.

I agree but see the counter argument above. If the code accessing the
database is perfect it shouldn't need to worry about abandoned connections.

> The Jetty session manager is storing HTTP session data in the
> database, and it does acquire connections directly from the pool.  I
> haven't dug through the Jetty source to see if they are doing anything
> questionable, tho I did email their user list about this issue.

I don't see anything that jumps out at me but there is the "Why does it
need to managed abandoned connections?" question.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to