[ 
https://issues.apache.org/jira/browse/DERBY-3693?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Knut Anders Hatlen updated DERBY-3693:
--------------------------------------

    Attachment: d3693.java

Attached is a small test case that reproduces the problem. It creates a 
deadlock between two transactions by first obtaining shared locks on the rows 
in SYSSTATEMENTS for getTables and getColumns in both transactions. Then one 
transaction tries to obtain an exclusive lock on the getTables row (because it 
needs to compile getTables), and the other transaction on getColumns. This 
results in the following error and stack trace:

ERROR 40001: A lock could not be obtained due to a deadlock, cycle of locks and 
waiters is:
Lock : ROW, SYSSTATEMENTS, (15,7)
  Waiting XID : {149, X} , APP, EXECUTE STATEMENT SYS."getTables"
  Granted XID : {149, S} , {148, S} 
Lock : ROW, SYSSTATEMENTS, (19,6)
  Waiting XID : {148, X} , APP, EXECUTE STATEMENT SYS."getColumns"
  Granted XID : {148, S} , {149, S} 
. The selected victim is XID : 149.
        at 
org.apache.derby.iapi.error.StandardException.newException(StandardException.java:303)
        at 
org.apache.derby.impl.services.locks.Deadlock.buildException(Deadlock.java:361)
        at 
org.apache.derby.impl.services.locks.ConcurrentLockSet.lockObject(ConcurrentLockSet.java:613)
        at 
org.apache.derby.impl.services.locks.AbstractPool.lockObject(AbstractPool.java:117)
        at 
org.apache.derby.impl.services.locks.ConcurrentPool.lockObject(ConcurrentPool.java:28)
        at 
org.apache.derby.impl.store.raw.xact.RowLocking3.lockRecordForWrite(RowLocking3.java:248)
        at 
org.apache.derby.impl.store.access.heap.HeapController.lockRow(HeapController.java:504)
        at 
org.apache.derby.impl.store.access.heap.HeapController.lockRow(HeapController.java:638)
        at 
org.apache.derby.impl.store.access.btree.index.B2IRowLocking3.lockRowOnPage(B2IRowLocking3.java:335)
        at 
org.apache.derby.impl.store.access.btree.index.B2IRowLocking3._lockScanRow(B2IRowLocking3.java:628)
        at 
org.apache.derby.impl.store.access.btree.index.B2IRowLockingRR.lockScanRow(B2IRowLockingRR.java:112)
        at 
org.apache.derby.impl.store.access.btree.BTreeForwardScan.fetchRows(BTreeForwardScan.java:304)
        at 
org.apache.derby.impl.store.access.btree.BTreeScan.fetchNext(BTreeScan.java:1809)
        at 
org.apache.derby.impl.sql.catalog.TabInfoImpl.updateRow(TabInfoImpl.java:1085)
        at 
org.apache.derby.impl.sql.catalog.TabInfoImpl.updateRow(TabInfoImpl.java:975)
        at 
org.apache.derby.impl.sql.catalog.DataDictionaryImpl.updateSPS(DataDictionaryImpl.java:4042)
        at 
org.apache.derby.iapi.sql.dictionary.SPSDescriptor.updateSYSSTATEMENTS(SPSDescriptor.java:1104)
        at 
org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(SPSDescriptor.java:728)
        at 
org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(SPSDescriptor.java:642)
        at 
org.apache.derby.impl.sql.compile.ExecSPSNode.generate(ExecSPSNode.java:177)
        at 
org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:447)
        at 
org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:88)
        at 
org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:794)
        at 
org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(EmbedPreparedStatement.java:128)
        at 
org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(EmbedPreparedStatement20.java:82)
        at 
org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(EmbedPreparedStatement30.java:63)
        at 
org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(EmbedPreparedStatement40.java:40)
        at 
org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Driver40.java:105)
        at 
org.apache.derby.impl.jdbc.EmbedConnection.prepareMetaDataStatement(EmbedConnection.java:2624)
        at 
org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.prepareSPS(EmbedDatabaseMetaData.java:3657)
        at 
org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.getPreparedQueryUsingSystemTables(EmbedDatabaseMetaData.java:3493)
        at 
org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.getPreparedQuery(EmbedDatabaseMetaData.java:3542)
        at 
org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.getPreparedQuery(EmbedDatabaseMetaData.java:3567)
        at 
org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.getTables(EmbedDatabaseMetaData.java:1708)
        at d3693.T1(d3693.java:57)
        at d3693.main(d3693.java:32)


I'm not sure how this could happen in a normal application, though.

> Deadlocks accessing DB metadata
> -------------------------------
>
>                 Key: DERBY-3693
>                 URL: https://issues.apache.org/jira/browse/DERBY-3693
>             Project: Derby
>          Issue Type: Bug
>          Components: JDBC
>    Affects Versions: 10.3.2.1, 10.3.3.0, 10.4.1.3
>         Environment: Linux amd64 or Windows 32bit
>            Reporter: Svata Dedic
>         Attachments: d3693.java, deadlock.diff
>
>
> My code changes DB structure (create a column), then immediately after 
> setting autocommit back to true, the code rescans the DB metadata
> DatabaseMetaData.getColumns(catalog, schemaName, tableName, null);
> I am sometimes getting a deadlock with these operations:
> 2008-04-16 19:50:47.833 GMT Thread[Default RequestProcessor,1,system] (XID = 
> 569844), (SESSIONID = 2), (DATABASE = /..../a3/.config/localdb/db), (DRDAID = 
> null), Cleanup action starting 2008-04-16 19:50:47.833 GMT Thread[Default 
> RequestProcessor,1,system] (XID = 569844), (SESSIONID = 2),  (DATABASE = 
> /..../IJCProjects/a3/.config/localdb/db), (DRDAID = null), Failed Statement 
> is: EXECUTE STATEMENT SYS."getColumns" ERROR 40XL2: A lock could not be 
> obtained within the time requested.
> The lockTable dump is:
> 2008-04-16 19:50:47.796 GMT
> XID       |TYPE         |MODE|LOCKCOUNT|LOCKNAME                              
>                    |STATE|TABLETYPE /LOCKOBJ                   |INDEXNAME / 
> CONTAINER_ID / MODE for LATCH only)  |TABLENAME / CONGLOM_ID                |
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> *** The following row is the victim ***
> 569852    |ROW          |X   |0        |(44,7)                                
>                 |WAIT |S                      |NULL |SYSSTATEMENTS            
>              | 
> *** The above row is the victim ***
> The stacktrace of the operation causing the deadlock is 
>         at org.apache.derby.iapi.error.StandardException.newException(Unknown 
> Source)
>         at 
> org.apache.derby.impl.services.locks.Timeout.createException(Unknown Source)
>         at 
> org.apache.derby.impl.services.locks.Timeout.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.RowLocking3.lockRecordForWrite(Unknown 
> Source)
>         at 
> org.apache.derby.impl.store.access.heap.HeapController.lockRow(Unknown Source)
>         at 
> org.apache.derby.impl.store.access.heap.HeapController.lockRow(Unknown Source)
>         at 
> org.apache.derby.impl.store.access.btree.index.B2IRowLocking3.lockRowOnPage(Unknown
>  Source)
>         at 
> org.apache.derby.impl.store.access.btree.index.B2IRowLocking3._lockScanRow(Unknown
>  Source)
>         at 
> org.apache.derby.impl.store.access.btree.index.B2IRowLockingRR.lockScanRow(Unknown
>  Source)
>         at 
> org.apache.derby.impl.store.access.btree.BTreeForwardScan.fetchRows(Unknown 
> Source)
>         at 
> org.apache.derby.impl.store.access.btree.BTreeScan.fetchNext(Unknown Source) 
>         at org.apache.derby.impl.sql.catalog.TabInfoImpl.updateRow(Unknown 
> Source) 
>         at org.apache.derby.impl.sql.catalog.TabInfoImpl.updateRow(Unknown 
> Source)
>         at 
> org.apache.derby.impl.sql.catalog.DataDictionaryImpl.updateSPS(Unknown Source 
> )
>         at 
> org.apache.derby.iapi.sql.dictionary.SPSDescriptor.updateSYSSTATEMENTS(Unknown
>  Source)
>         at 
> org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(Unknown
>  Source)
>         at 
> org.apache.derby.iapi.sql.dictionary.SPSDescriptor.getPreparedStatement(Unknown
>  Source)
>         at org.apache.derby.impl.sql.compile.ExecSPSNode.generate(Unknown 
> Source)
>         at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown 
> Source)
>         at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source)
>         at 
> org.apache.derby.impl.sql.GenericPreparedStatement.rePrepare(Unknown Source)
>         at org.apache.derby.impl.sql.GenericPreparedStatement.execute(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.executeQuery(Unknown 
> Source) 
>         at org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.doGetCols(Unknown 
> Source)
>         at 
> org.apache.derby.impl.jdbc.EmbedDatabaseMetaData.getColumns(Unknown Source)
> I've seen the deadlock occur during several get-metadata operations 
> (getImportedKeys, ...), each time waiting on the SYSSTATEMENTS apparently 
> because of internally constructed PreparedStatement. The lock eventually 
> times out and the locked out operation completes without error.
> When the deadlock occurs, the "real" SQL into systables is being compiled (I 
> traced this sql to be the value of "getColumns" key in 
> org/apache/derby/impl/jdbc/metadata.properties file):
> ---------%<-----------------------%<--------------
> Begin compiling prepared statement: SELECT CAST ('' AS VARCHAR(128)) AS 
> PKTABLE_CAT, S.SCHEMANAME AS PKTABLE_SCHEM, TABLENAME AS
> PKTABLE_NAME, COLS.COLUMNNAME AS PKCOLUMN_NAME, CAST ('' AS VARCHAR(128)) AS 
> FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, FKCOLUMN_NAME, CAST ...
> ---------%<-----------------------%<--------------

-- 
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