You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-dev@db.apache.org by "Dag H. Wanvik (JIRA)" <ji...@apache.org> on 2014/03/06 13:26:43 UTC

[jira] [Commented] (DERBY-6497) Deadlock with OnDelete="CASCADE"

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

Dag H. Wanvik commented on DERBY-6497:
--------------------------------------

Would you be able to attach the repro code to this issue? That will make it quicker for one of the devs to check this one out. Thanks.


> Deadlock with OnDelete="CASCADE"
> --------------------------------
>
>                 Key: DERBY-6497
>                 URL: https://issues.apache.org/jira/browse/DERBY-6497
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.10.1.1
>         Environment: Tested in Linux, Window, Unix with Java 7 1.7.0_40
>            Reporter: Billow Gao
>            Priority: Critical
>
> We saw error like:
> java.sql.SQLTransactionRollbackException: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:..
> We had two tables, one is parent, the other one is a child with foreign key on parent's id column. We set OnDelete='CASCADE' to delete related records from the child table.
> The problem: if we have one thread inserting to parent/child table, another thread deleting from the parent table, then we will hit the deadlock. To confirm, I wrote an unit to verify and it could reproduce the issue. If we remove the OnDelete='CASCADE', and delete record from the child table, then the issue is gone.
> When I turn on the query plan log, we found out:
> when it's deleting records from child table, it's using table lock.
> Index Scan ResultSet for childTable using index On Foreign Key at serializable isolation level using exclusive table locking chosen by the optimizer"
> We had index on the id field so it should be using index.
> But it picked the scan with table lock which caused the dead lock.
>  
> 1. working case Without OnDelete='CASCADE'
>     delete from childTable where id IN (SELECT id from parentTable where msgId='xxxx')
>     delete from parentTable where msgId='xxx'
> It's using row locking, and worked fine
> 2. deadlock case WITH OnDelete='CASCADE'
>     delete from parentTable where msgId='xxx'
>     It's using table locking on the childTable which introduced the deadlock.
> Our unit test setup:
> Thread 1:
>     1.1 insert into parentTable ...
>     1.2 insert into childTable....
> Thread 2:
>      2.1  When OnDelete='CASCADE' is set
>             Delete from parentTable where msgId='xxx'
>             => DEAD lock
>      2.2 When OnDelete='CASCADE' is NOT set
>             delete from childTable where id IN (SELECT id from parentTable where msgId='xxxx')
>     delete from parentTable where msgId='xxx'
>              => working
> {code}
> java.sql.SQLTransactionRollbackException: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
> Lock : ROW, parentTable, (2,6)
>   Waiting XID : {668, U} , APP, delete from parentTable where msgId = ?
>   Granted XID : {669, X} 
> Lock : TABLE, childTable, Tablelock
>   Waiting XID : {669, IS} , APP, insert into childTable (id, recipient) values (?, ?)
>   Granted XID : {668, X} 
> . The selected victim is XID : 668.
> 	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
> 	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
> 	at org.apache.derby.impl.jdbc.EmbedPreparedStatement.execute(Unknown Source)
> 	at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
> 	at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
>     ........
> 	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
> 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
> 	at java.lang.Thread.run(Unknown Source)
> Caused by: java.sql.SQLException: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
> Lock : ROW, parentTable, (2,6)
>   Waiting XID : {668, U} , APP, delete from parentTable where msgId = ?
>   Granted XID : {669, X} 
> Lock : TABLE, childTable, Tablelock
>   Waiting XID : {669, IS} , APP, insert into childTable (id, recipient) values (?, ?)
>   Granted XID : {668, X} 
> . The selected victim is XID : 668.
> 	at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
> 	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
> 	... 23 more
> Caused by: ERROR 40001: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
> Lock : ROW, parentTable, (2,6)
>   Waiting XID : {668, U} , APP, delete from parentTable where msgId = ?
>   Granted XID : {669, X} 
> Lock : TABLE, childTable, Tablelock
>   Waiting XID : {669, IS} , APP, insert into childTable (id, recipient) values (?, ?)
>   Granted XID : {668, X} 
> . The selected victim is XID : 668.
> 	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
> 	at org.apache.derby.impl.services.locks.Deadlock.buildException(Unknown Source)
> 	at org.apache.derby.impl.services.locks.ConcurrentLockSet.lockObject(Unknown Source)
> 	at org.apache.derby.impl.services.locks.AbstractPool.lockObject(Unknown Source)
> 	at org.apache.derby.impl.services.locks.ConcurrentPool.lockObject(Unknown Source)
> 	at org.apache.derby.impl.store.raw.xact.RowLocking2.lockRecordForRead(Unknown Source)
> 	at org.apache.derby.impl.store.access.conglomerate.OpenConglomerate.lockPositionForRead(Unknown Source)
> 	at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(Unknown Source)
> 	at org.apache.derby.impl.store.access.heap.HeapScan.fetchNext(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.TableScanResultSet.getNextRowCore(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.ProjectRestrictResultSet.getNextRowCore(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.DMLWriteResultSet.getNextRowCore(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.DeleteResultSet.collectAffectedRows(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.DeleteCascadeResultSet.collectAffectedRows(Unknown Source)
> 	at org.apache.derby.impl.sql.execute.DeleteCascadeResultSet.open(Unknown Source)
> 	at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
> 	at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
> 	... 17 more
> {code}



--
This message was sent by Atlassian JIRA
(v6.2#6252)