db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Knut Anders Hatlen (JIRA)" <j...@apache.org>
Subject [jira] Commented: (DERBY-4279) Statement cache deadlock
Date Wed, 16 Jun 2010 17:12:23 GMT

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

Knut Anders Hatlen commented on DERBY-4279:

> The original still had a synchronized block that synchronized on the
> prepared statement. Was it unnecessary? I'm not so sure...

The original synchronization block enclosed code that accessed the
prepared statement, which may be shared between threads. So that
synchronization should not be removed, I was only talking about the
synchronization blocks that were added by the patch.

> One concern is the statement above "GenericActivationHolder instances
> are private to a transaction". Private to a transaction, and private
> to a thread are two different things. We run in an XA environment, and
> theoretically (as far as I understand XA), a transaction can span both
> connections and threads.

In this case, "private to a transaction" meant "private to a local
Derby transaction", so XA won't come into the picture. Still, it's
true that a single transaction can run in multiple threads. For
example, I can prepare a statement in one thread, execute the
statement in another thread, and commit the transaction in a third
thread. However, there's synchronization at a higher level that
prevents multiple threads from running in the same transaction
concurrently. This is ensured at the entry points in EmbedConnection,
EmbedStatement and EmbedResultSet. The engine code therefore safely
assumes that "private to a transaction" implies "not accessed by
multiple threads concurrently".

> Another issue, is that, when running with the above patch I am seeing
> intermittent failures in our server application. There are multiple
> threads doing "DELETE FROM" and "INSERT INTO" the same table, and I am
> seeing an occasional insert failure stating that the insert would
> cause a primary key violation.
> At this point, I am not sure it is related to the patch or not because
> our server code has been shifting about as well. However, a short run
> using without the patch did not see this particular
> error. Because the issue is intermittent, and I unsure whether the
> cause is the patch or application level code. Further testing tomorrow
> should clarify.

Thanks for investigating this further. It would be good to understand
why you see this error before we proceed with getting the patch into
the code tree.

> Note that running the derby test suite did not result in any errors.

Yes, the regression test suite doesn't have many multi-threaded tests
and isn't good at catching such errors, unfortunately...

> Statement cache deadlock
> ------------------------
>                 Key: DERBY-4279
>                 URL: https://issues.apache.org/jira/browse/DERBY-4279
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions:,,,,,
>         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.

View raw message