Question

Why would a process running a transaction at RC isolation level hold an IX page lock if it is already running a select statement on another table? I mean, i thought that locks are released when the statement finishes (that is why we could have non-repeatable reads).

Here's the deadlock xml:

<deadlock-list>
 <deadlock victim="process5cd048">
  <process-list>
   <process id="process5cd048" taskpriority="0" logused="10000" waittime="2220" schedulerid="3" kpid="5764" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" lastattention="2012-11-08T17:33:28.597" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))    </inputbuf>
   </process>
   <process id="process33ebc8" taskpriority="0" logused="10676" waitresource="PAGE: 5:1:1144344" waittime="2221" ownerId="1157173773" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.197" XDES="0x41518b140" lockMode="S" schedulerid="5" kpid="5272" status="suspended" spid="62" sbid="0" ecid="9" priority="0" trancount="0" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
    </inputbuf>
   </process>
   <process id="process4e13048" taskpriority="0" logused="11448" waitresource="PAGE: 5:1:1144209" waittime="2172" ownerId="1157175935" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.997" XDES="0x3458e63b0" lockMode="S" schedulerid="7" kpid="3912" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:53.070" lastbatchcompleted="2012-11-09T12:16:53.067" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157175935" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="160" sqlhandle="0x02000000193c8a3bb37a516f7a7155b01a67b7772459f53e">
SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@Level int,@StatusInProgress int,@StatusConfirmed int,@StockContainerID bigint)SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <exchangeEvent id="Pipe43a6da400" WaitType="e_waitPipeGetRow" nodeId="1">
    <owner-list>
     <owner id="process33ebc8"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5cd048"/>
    </waiter-list>
   </exchangeEvent>
   <pagelock fileid="1" pageid="1144344" dbid="5" objectname="WebPortal.dbo.WP_CashCenter_StockTransactionLine" id="lock326ee4180" mode="IX" associatedObjectId="72057594149601280">
    <owner-list>
     <owner id="process4e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process33ebc8" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <pagelock fileid="1" pageid="1144209" dbid="5" objectname="WebPortal.dbo.WP_Discrepancy" id="lock339da6b80" mode="SIX" associatedObjectId="72057594163625984">
    <owner-list>
     <owner id="process5cd048" mode="SIX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process4e13048" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>

As you can see process process4e13048 holds an IX lock on some page of table WP_CashCenter_StockTransactionLine. The current statement trying to execute is a SELECT which cannot finish, because it wants a shared lock on page of WP_Discrepancy (which is obvious) conflicting with SIX lock held by process process5cd048.

Again, why would the latter process hold that SIX lock? According to execution stack the statement being executed is a SELECT to WP_CashCenter_StockTransactionLine table.

I would expect the locks acquired by previous statements within the same process to preserve if I was running a transaction with Serializable IL. But that's not the case.

Can anybody explain me what did I get wrong about RC isolation level. Thanks.

Was it helpful?

Solution

I thought that locks are released when the statement finishes

Not write locks (X, IX, S-IX etc). Write locks must obey two phase locking so they are released at the end of the transaction. Think what would the opposite mean: a DELETE releases the X lock on the row deleted before the transaction ends, later a concurrent transaction INSERTs a new row with the same key (it can, since there is no lock) and now the first transaction wants to roll back. What could it do, it cannot insert back the row it deleted because the key was taken in the meantime by the second transaction, so it cannot rollback.

So a deadlock can occur when running SELECTs because the transaction running those selects had acquired write locks before running the SELECT.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top