[ 
https://issues.apache.org/jira/browse/DERBY-4279?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12878829#action_12878829
 ] 

Brett Wooldridge commented on DERBY-4279:
-----------------------------------------

Attached is a new patch with narrowed synchronization in 
GenericActivationHolder.  Still, the synchronization is not the same as 
previously because I think that synchronization was wrong.

The previous code had this logic OUTSIDE of synchronized blocks:

284     newGC = gc;
296     BaseActivation newAC = (BaseActivation) newGC.newInstance(lcc);
298     DataTypeDescriptor[]  newParamTypes = ps.getParameterTypes();

then later:
333     ac = newAC;
334     gc = newGC;
335     paramTypes = newParamTypes;
...
352     return ac.execute();  <-- Particularly dangerous

These unprotected accesses (both read and write) to member variables shared by 
multiple threads is inherently dangerous.

The new patch for GenericActivationHolder takes the approach of copying the 
member variables into local variables within a synchronized block, and then 
using those locals throughout.  At the end of the code path where a statement 
is re-prepared (and a new generated class, activation class, and parameter 
types created), the member variables are then updated within a synchronized 
block.

I believe this approach should eliminate all synchronization issues within the 
execute() method while minimizing the synchronization windows.



> Statement cache deadlock
> ------------------------
>
>                 Key: DERBY-4279
>                 URL: https://issues.apache.org/jira/browse/DERBY-4279
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.0.2.1, 10.1.3.1, 10.2.2.0, 10.3.3.0, 10.4.2.0, 
> 10.5.1.1
>         Environment: Windows Vista
>            Reporter: Jeff Stuckman
>            Assignee: Brett Wooldridge
>         Attachments: Derby4279.java, patch4279.txt, stacktrace.txt
>
>
> Due to a design flaw in the statement cache, a deadlock can occur if a 
> prepared statement becomes out-of-date.
> I will illustrate this with the following example:
> The application is using the embedded Derby driver. The application has two 
> threads, and each thread uses its own connection.
> There is a table named MYTABLE with column MYCOLUMN.
> 1. A thread prepares and executes the query SELECT MYCOLUMN FROM MYTABLE. The 
> prepared statement is stored in the statement cache (see 
> org.apache.derby.impl.sql.GenericStatement for this logic)
> 2. After some time, the prepared statement becomes invalid or out-of-date for 
> some reason (see org.apache.derby.impl.sql.GenericPreparedStatement)
> 3. Thread 1 begins a transaction and executes LOCK TABLE MYTABLE IN EXCLUSIVE 
> MODE
> 4. Thread 2 begins a transaction and executes SELECT MYCOLUMN FROM MYTABLE. 
> The statement is in the statement cache but it is out-of-date. The thread 
> begins to recompile the statement. To compile the statement, the thread needs 
> a shared lock on MYTABLE. Thread 1 already has an exclusive lock on MYTABLE. 
> Thread 2 waits.
> 5. Thread 1 executes SELECT MYCOLUMN FROM MYTABLE. The statement is in the 
> statement cache but it is being compiled. Thread 1 waits on the statement's 
> monitor.
> 6. We have a deadlock. Derby eventually detects a lock timeout, but the error 
> message is not descriptive. The stacks at the time of the deadlock are:
> This deadlock is unique because it can still occur in a properly designed 
> database. You are only safe if all of your transactions are very simple and 
> cannot be interleaved in a sequence that causes the deadlock, or if your 
> particular statements do not require a table lock to compile. (For the sake 
> of simplicity, I used LOCK TABLE in my example, but any UPDATE statement 
> would fit.)

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to