It seems that index locks are not held for the entire transaction period. I think the main problem is that transaction 1 does the same UPDATE twice, but it needs to get more locks to execute the second UPDATE .
According to docs , index locks are held for a short time. Unlike data locks, they are not saved until the transaction is completed. Let's look at the chart in more detail.
Transaction 1 does the first UPDATE . This gets the row level lock in row in apples . During the operation, it also gets an index lock in trees . The transaction has not yet been completed, so row-level data locks are still held by passing 1. However, index lock on trees immediately released. Not sure why Postgres does this for all types of indexes.
Transaction 2 comes and blocks trees for updating. This blocks both data and index. This is not blocked because transaction 1 has already issued an index lock. This time both locks are held until the end of the transaction. You do not know why this index lock is held and the other is released.
Trade 1 returns and tries UPDATE again. Locking on apples great, as it already is. The lock on trees , however, is blocked because Transaction 2 already has it.
Adding UPDATE to transaction 2 causes it to wait for transaction 1, causing a deadlock.
EDIT:
I came back to investigate this a bit more when I have Postgres installed. This is actually really weird. I looked at pg_locks after transaction 2.
Transaction 1 has the following locks:
- RowExclusive on apples_pkey and apples
- Exclusive on its transaction and virtualxid
Transaction 2 has the following locks (and many other irrelevant ones):
- AccessShare on trees_pkey
- RowShare in the trees
- Exclusive on its transaction and virtualxid
- RowExclusive on apples_pkey and apples
- Exclusive on the tuple in apples
Transaction 2 also expects to receive a Share lock on transaction 1.
Interestingly, two transactions may contain a RowExclusive lock in the same table . However, exclusive locks conflict with Share, so transaction 2 expects transaction ID 1 of the transaction. docs mentions transaction blocking as a way to wait for another transaction. Therefore, it appears that transaction 2, although complete, is still waiting for transaction 1.
When transaction 1 continues, she wants to acquire a Share lock on transaction 2, and this creates a dead end. Why does he want to acquire a block of shares on transaction 2? Not too sure about that. Documents indicate that this information is not available in pg_locks . I'm going to guess that this is related to MVCC, but for me this is still a mystery.