You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sebb <se...@gmail.com> on 2008/06/27 13:18:06 UTC

[DBCP] how does narrowing the lock help with deadlock in DBCP-270?

On 27/06/2008, psteitz@apache.org <ps...@apache.org> wrote:
> Author: psteitz
>  Date: Thu Jun 26 19:48:06 2008
>  New Revision: 672097
>
>  URL: http://svn.apache.org/viewvc?rev=672097&view=rev
>  Log:
>  Narrowed synchronization in AbandonedTrace to resolve an Evictor deadlock.
>  JIRA: DBCP-270
>  Reported and patched by Filip Hanik.
>

I've had a look at the patch and the JIRA, and I don't understand how
narrowing the lock works here.

Originally, the code locked on "this", whereas now the code uses "this.trace".

However, as far as I can see, no objects were taken out of the locked
blocks, and there is no other synchronization in the class. So what
else was locking on "this"?

So how does the change of lock object actually help here?

Or is it just a byproduct of the synchronisation that was added to
getTrace() as part of the patch?

The lock details provided in the JIRA don't show any locks on the
AbandonedTrace object - but this info could have been omitted.

I'm not saying that the patch is wrong, but I would like to understand
how it helps!

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [DBCP] how does narrowing the lock help with deadlock in DBCP-270?

Posted by Phil Steitz <ph...@steitz.com>.
sebb wrote:
> On 27/06/2008, psteitz@apache.org <ps...@apache.org> wrote:
>   
>> Author: psteitz
>>  Date: Thu Jun 26 19:48:06 2008
>>  New Revision: 672097
>>
>>  URL: http://svn.apache.org/viewvc?rev=672097&view=rev
>>  Log:
>>  Narrowed synchronization in AbandonedTrace to resolve an Evictor deadlock.
>>  JIRA: DBCP-270
>>  Reported and patched by Filip Hanik.
>>
>>     
>
> I've had a look at the patch and the JIRA, and I don't understand how
> narrowing the lock works here.
>
> Originally, the code locked on "this", whereas now the code uses "this.trace".
>
> However, as far as I can see, no objects were taken out of the locked
> blocks, and there is no other synchronization in the class. So what
> else was locking on "this"?
>
> So how does the change of lock object actually help here?
>
> Or is it just a byproduct of the synchronisation that was added to
> getTrace() as part of the patch?
>
> The lock details provided in the JIRA don't show any locks on the
> AbandonedTrace object - but this info could have been omitted.
>
> I'm not saying that the patch is wrong, but I would like to understand
> how it helps!
>   
Good questions and thanks for reviewing.  Even greater thanks for 
jumping in to DBCP and/or POOL :)

Now to the inscrutable world of DBCP...

PoolableConnection extends DelegatingConnection which extends 
AbandonedTrace.   The deadlock sequence in DBCP-270 is

1) DBCP client thread invokes close on PoolableConnection.  This method 
is synchronized, so locks the PC.
2) Close for a PC means return to pool, so the associated 
GenericObjectPool's returnObject is invoked.  This calls 
GOP.addObjectToPool.  Neither of these methods are synchronized, but 
addObjectToPool includes two synchronized blocks, both of which lock the 
pool.  The client thread makes it past the first block, which returns 
the connection to the pool, but before it can acquire the pool lock for 
the second block (to decrement the number of active connections),
3) The (dreaded) Evictor kicks off, locks the pool and attempts to 
validate the connection that was just returned.  Validation involves 
executing a query.  Due to another painful-to-maintain feature of DBCP, 
when a DelegatingConnection creates a statement, it registers itself as 
the source of the statement by passing a reference to itself to the 
DelegatingStatement that its createStatement creates.  The way this 
actually works is that the DelegatingStatement constructor ends up 
adding the DelegatingStatement to the trace property of the 
DelegatingConnection.  This happens via the DelegatingConnection's 
addTrace method (from AbandonedTrace).  Before the patch, addTrace 
protected the trace in a block synchronized on *this, locking the 
DelegatingConnection.  This led to deadlock, since the client thread 
acquired that lock in 1).  Reducing scope to the trace eliminates this 
contention.  A workaround is to turn off testWhileIdle, or avoid using 
the Evictor altogether.

This is a good change for DBCP which makes progress toward addressing 
the basic problem of client and evictor contention for locks.  There are 
others in DBCP-44.  The deadlock reported in DBCP-270 is the same as the 
last one mentioned in DBCP-44, which is new with POOL 1.4, where the 
synchroniztion in addObjectToPool was broken into two blocks.  That 
change was made to a) keep factory methods out of pool-synchronized 
scope (which was killing performance) and b) wait to decrement 
activeCount until objects destroyed on return are destroyed.  The 
general problem of preventing Evictor access to objects being borrowed 
or returned is documented in POOL-125.   I have a patch for this that I 
am testing.

Thanks in advance for any ideas, patches or RM-volunteering to help get 
DBCP 1.3 and/or POOL 1.5 out.  We should cut a DBCP release as soon as 
we can organize it to fix this and the several other issues that have 
been addressed in trunk. 

Phil

 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org