Thread: "deadlock detected" documentation

"deadlock detected" documentation

From
Matt Mello
Date:
I just got a "deadlock detected" SQL error from the backend.  I've never 
received one of these before, but I just released new pooling code, so 
I'm concerned.

Can someone point me to documentation on what this is and how to prevent 
it?  [My search on the newsgroups yielded far too much for me to read.]

TIA!

-- 
Matt Mello



Re: "deadlock detected" documentation

From
"A.Bhuvaneswaran"
Date:
> I just got a "deadlock detected" SQL error from the backend.  I've never 
> received one of these before, but I just released new pooling code, so 
> I'm concerned.
> 
> Can someone point me to documentation on what this is and how to prevent 
> it?  [My search on the newsgroups yielded far too much for me to read.]

Deadlock occurs when two transactions try to wait for each other. In other
words, if two processes try to update two tables which have a reference to
same table, deadlock is detected. I donot know whether it is a bug or
bottle neck in postgresql. Mostly it can be avoided using locks. For
details, refer,
http://www.postgresql.org/docs/view.php?version=7.3&idoc=1&file=sql-lock.html

regards,
bhuvaneswaran



Re: "deadlock detected" documentation

From
Tom Lane
Date:
Matt Mello <alien@spaceship.com> writes:
> I just got a "deadlock detected" SQL error from the backend.  I've never 
> received one of these before, but I just released new pooling code, so 
> I'm concerned.

> Can someone point me to documentation on what this is and how to prevent 
> it?  [My search on the newsgroups yielded far too much for me to read.]

It means user A is waiting for a lock held by user B, while user B
is waiting for a lock held by user A.  For better info you'll need
to offer more details about what your applications are doing ...
        regards, tom lane



Re: "deadlock detected" documentation

From
Matt Mello
Date:
 From what I understand, two UPDATEs are trying to update different 
fields of the same records at the same time.  Sometimes one of the 
updates gets this error, sometimes the other.  I can code around it, but 
I want to be able to prevent this in new situations in the future.

Here are the updates:
UPDATE txn
SET batchid = 19391
WHERE  txn.terminalid = 38 AND yadayada

UPDATE txn
SET drawerid = 50123
WHERE txn.terminalid = 38 AND yadayada

The above updates tend to operate on 500 records each.

Under some situations the EXACT same records get hit at the EXACT same time.

I did the same thing with informix and had no trouble.  I'm wondering 
how the locks differ and what I can do to resolve this.  I guess the 
problem is that the two updates hit the records in different orders (as 
though they were going in opposite directions through the list), so they 
end up waiting on each other in a deadlock -- my bad luck, I guess.

Instead, I *could* select the primary keys based on the where clauses 
above, then loop and update each of the records independetly, one at a 
time, however that is slow and cumbersome.  Once I have converted to a 
full-fledged application server, I WILL be updating a single record at a 
time anyway, so I suppose I ought to just go ahead and do that.  :(

If I do that, and I have two threads on two different connections, both 
starting a txn then updating a list of records (both using the same 
list), might this happen then, too?  I mean, is the problem that it is 
all happening inside 2 long transactions, or does this only happen with 
multi-record-update statements?

Thanks!


Tom Lane wrote:
> 
>>I just got a "deadlock detected" SQL error from the backend.  I've never 
>>received one of these before, but I just released new pooling code, so 
>>I'm concerned.
> 
> It means user A is waiting for a lock held by user B, while user B
> is waiting for a lock held by user A.  For better info you'll need
> to offer more details about what your applications are doing ...
> 
>             regards, tom lane
> 

-- 
Matt Mello



Re: "deadlock detected" documentation

From
Tom Lane
Date:
Matt Mello <alien@spaceship.com> writes:
>  From what I understand, two UPDATEs are trying to update different 
> fields of the same records at the same time.  Sometimes one of the 
> updates gets this error, sometimes the other.  I can code around it, but 
> I want to be able to prevent this in new situations in the future.

> Here are the updates:
> UPDATE txn
> SET batchid = 19391
> WHERE  txn.terminalid = 38 AND yadayada

> UPDATE txn
> SET drawerid = 50123
> WHERE txn.terminalid = 38 AND yadayada

I can't see a reason for bare UPDATEs of that sort to get deadlocks.
There must be some other factor involved.  Do you have triggers, rules,
or foreign keys on this table?  Other locks being taken in the same
transaction?
        regards, tom lane


Re: "deadlock detected" documentation

From
Matt Mello
Date:
Tom Lane wrote:> I can't see a reason for bare UPDATEs of that sort to get deadlocks.> There must be some other factor
involved. Do you have triggers, rules,> or foreign keys on this table?  Other locks being taken in the same>
transaction?

We haven't finished implementing our transaction system yet, so no, 
there are no other things running in the txn.  Each of those statements 
is a complete txn.  <blush>

This problem only happens on our production server (Murphy's Law).  I 
haven't been able to duplicate it on our test system.  The production 
system is a heavily multi-threaded environment that has lots of data 
entering the system all the time.  This makes it difficult to detect 
which SQL statements are affecting each other.  :(

There are no triggers or rules except for the foreign keys.

The txn table has several foreign keys.  The two that seem to be of 
interest are:
txn.drawerid -> drawer.drawerid
txn.batchid -> batch.batchid

I certainly don't mind posting a LOT more info on this.  I just didn't 
want to spam the list with useless information.  If I understood more 
about what can cause this kind of error, I could probably find and post 
the pertinent info.  Can I assume that a plain old select has nothing to 
do with this?  If so, I can remove the select's from my log and that 
will eliminate about 80% of the SQL, making it easier to tell what is 
happening.

Thanks, Tom!


-- 
Matt Mello



Re: "deadlock detected" documentation

From
Tom Lane
Date:
Matt Mello <alien@spaceship.com> writes:
> There are no triggers or rules except for the foreign keys.
> The txn table has several foreign keys.

You are probably getting deadlocks on the rows referenced by the foreign
keys, then.  As of the current release, each UPDATEd row will cause the
foreign-key triggers to grab a row lock (SELECT FOR UPDATE lock) on the
referenced row in the other table.  If you have concurrent updates
touching rows that reference the same other-table rows, it's possible to
get a deadlock depending on the order in which the updates happen to
occur.

There is no particularly good SQL-level workaround for this; the only
one I can think of is to do the updates one row at a time (or at least
one foreign-key value at a time), which sucks.

There is a patch in CVS tip that alleviates the problem substantially
by not taking a foreign-table lock when the foreign key value isn't
being changed by the UPDATE, which is commonly the case (although I'm
not entirely sure that it will help you, since you do seem to be
updating the referencing column).  If you want to try it, I believe Jan
Wieck posted a 7.3 version of the patch a month or so ago.
        regards, tom lane


Re: "deadlock detected" documentation

From
Matt Mello
Date:
Tom Lane wrote:> You are probably getting deadlocks on the rows referenced by the foreign> keys, then.  As of the
currentrelease, each UPDATEd row will cause the> foreign-key triggers to grab a row lock (SELECT FOR UPDATE lock) on
the>referenced row in the other table.  If you have concurrent updates> touching rows that reference the same
other-tablerows, it's possible to> get a deadlock depending on the order in which the updates happen to> occur.
 
> There is a patch in CVS tip that alleviates the problem substantially> by not taking a foreign-table lock when the
foreignkey value isn't> being changed by the UPDATE, which is commonly the case (although I'm> not entirely sure that
itwill help you, since you do seem to be> updating the referencing column).  If you want to try it, I believe Jan>
Wieckposted a 7.3 version of the patch a month or so ago.
 

I see.  One item I forgot to mention ...  Both update statements have a 
where clause containing txn.terminalid=38.  Txn.terminalid is a foreign 
key column in that table (txn.terminalid->terminal.terminalid).  Could 
this be the source of the trouble?

If so, I can work around this for now, but the patch you mention sounds 
like it would work in almost all situations where this might adversely 
(and unexpectedly) affect us.

Thanks!

-- 
Matt Mello



Re: "deadlock detected" documentation

From
Tom Lane
Date:
Matt Mello <alien@spaceship.com> writes:
> I see.  One item I forgot to mention ...  Both update statements have a 
> where clause containing txn.terminalid=38.  Txn.terminalid is a foreign 
> key column in that table (txn.terminalid->terminal.terminalid).  Could 
> this be the source of the trouble?

Not per se.  The problem depends on which rows get updated and in what
sequence --- the contents of the WHERE clause aren't the issue, except
insofar as they determine the set of rows to be updated.
        regards, tom lane


Re: "deadlock detected" documentation

From
Matt Mello
Date:
Okay, so one last question on this...

If I do the following, assuming I haven't applied the patch, will it 
still result in a deadlock (in other words, does this only happen with 
multi-record updates, or can it happen with independent single-record 
updates inside transactions)?

THREAD1:                                                THREAD2:

BEGIN;
update txn set ... where txn.terminalid = 1;
                                                          BEGIN;                    update txn set ... where
txn.terminalid= 2;
 

(I anticipate the next statement will give me a deadlock.)

update txn set ... where txn.terminalid = 2;
                    update txn set ... where txn.terminalid = 1;
COMMIT;
                                                         COMMIT;

Thanks, again!


Tom Lane wrote:
> Matt Mello <alien@spaceship.com> writes:
> 
>>I see.  One item I forgot to mention ...  Both update statements have a 
>>where clause containing txn.terminalid=38.  Txn.terminalid is a foreign 
>>key column in that table (txn.terminalid->terminal.terminalid).  Could 
>>this be the source of the trouble?
> 
> 
> Not per se.  The problem depends on which rows get updated and in what
> sequence --- the contents of the WHERE clause aren't the issue, except
> insofar as they determine the set of rows to be updated.
> 
>             regards, tom lane
> 
> 

-- 
Matt Mello
512-350-6900



Re: "deadlock detected" documentation

From
Matt Mello
Date:
Okay, I finally found in the docs where it says that all locks acquired 
continue until rollback or commit (end of txn), which answers my 
question in previous email (bottom).

So, it seems like having an UPDATE ... ORDER BY would help this.  At 
least I could force which order rows are locked that way.  As mentioned 
earlier, though, I can do that manually as multiple updates in a single 
transaction.

So, if I have 2 DB connections, and each one is doing the same update 
but on 2 different rows in the same table, and both of those rows have 
foreign keys to the same rows in other tables, is there a possibility 
that the foreign key locks could be acquired in different orders?  In 
other words, are there situations with foreign keys where the only way I 
can prevent a deadlock with update/insert is to NOT HAVE foreign keys?

The two situations I can think of are:
1) Two FK fields in a single row pointing to 2 different FK tables, for 
which any 2 updates get locks in opposite order (seems like a deadlock).
2) Two FK fields pointing to only 1 FK table (both fields are references 
to the same table), for which each update gets independent locks instead 
of one lock for both fields, so there is a potential that #1 problem 
could impact this as well.

Is this the right maillist for this?

Thanks again!


Matt Mello wrote:
> If I do the following, assuming I haven't applied the patch, will it 
> still result in a deadlock (in other words, does this only happen with 
> multi-record updates, or can it happen with independent single-record 
> updates inside transactions)?



Re: "deadlock detected" documentation

From
Tom Lane
Date:
Matt Mello <alien@spaceship.com> writes:
> The two situations I can think of are:
> 1) Two FK fields in a single row pointing to 2 different FK tables, for 
> which any 2 updates get locks in opposite order (seems like a deadlock).

I don't think this is possible, at least in 7.3.  All backends are
guaranteed to run the triggers of a given table in the same order,
so the foreign-row locks should be acquired in the same column order
in all cases.

> 2) Two FK fields pointing to only 1 FK table (both fields are references 
> to the same table), for which each update gets independent locks instead 
> of one lock for both fields, so there is a potential that #1 problem 
> could impact this as well.

Not clear what you mean by "independent locks"; there is only one row
lock on a row.

The cases that I'd be concerned about are not within-row conflicts, but
multi-row conflicts...
        regards, tom lane


Re: "deadlock detected" documentation

From
Jan Wieck
Date:
Tom Lane wrote:
> Matt Mello <alien@spaceship.com> writes:
> 
>>The two situations I can think of are:
>>1) Two FK fields in a single row pointing to 2 different FK tables, for 
>>which any 2 updates get locks in opposite order (seems like a deadlock).
> 
> 
> I don't think this is possible, at least in 7.3.  All backends are
> guaranteed to run the triggers of a given table in the same order,
> so the foreign-row locks should be acquired in the same column order
> in all cases.

Except the sessions set deferred modes differently.


Jan

-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #



Re: "deadlock detected" / cascading locks

From
Matt Mello
Date:
Jan, can you explain more to a newby like me what you mean by "the 
sessions set deferred modes differently?"

And, do these locks cascade?  If I choose to do an update on table A, 
and it has a foreign key to table B, which has a foreign key to table C, 
does the update-induced lock on A cause a lock on B /and/ C?

My entire system is setup with foreign keys.  Almost all of my tables 
are part of a "tree" of foreign keys, which can all be traced back to 
one root table.  If a lock on a leaf table causes locks all the way back 
to the root table, then foreign keys can't be used in my system (and it 
seems they wouldn't be useful in many other systems ... where this also 
true).

However, if the recent FK-lock bug fix stops this unnecessary locking, 
things should work well, I guess.  I have built and installed the 
7.3STABLE tip, but not tested this situation yet.

Thanks again!


Jan Wieck wrote:
> Tom Lane wrote:
> 
>> Matt Mello <alien@spaceship.com> writes:
>>
>>> The two situations I can think of are:
>>> 1) Two FK fields in a single row pointing to 2 different FK tables, 
>>> for which any 2 updates get locks in opposite order (seems like a 
>>> deadlock).
>>
>>
>>
>> I don't think this is possible, at least in 7.3.  All backends are
>> guaranteed to run the triggers of a given table in the same order,
>> so the foreign-row locks should be acquired in the same column order
>> in all cases.
> 
> 
> Except the sessions set deferred modes differently.
> 
> 
> Jan
> 

-- 
Matt Mello




Re: "deadlock detected" / cascading locks

From
Stephan Szabo
Date:
On Mon, 19 May 2003, Matt Mello wrote:

> Jan, can you explain more to a newby like me what you mean by "the
> sessions set deferred modes differently?"

If a constraint is deferred in one transaction and not in another the
order the locks are grabbed could be different.  For example you have two
constraints A and B, and two transactions T1 and T2.  T1 sets constraint A
to be deferred, T2 has constraint A being immediate. T1 will get the lock
for B first (at end of statement) and then get lock A second (at end of
transaction).  T2 will get lock A first (at end of statement) and B second
(at end of statement).  This could cause deadlock if both transactions do
something that locks the same rows for A and B and T1 gets the B lock,
then T2 gets the A lock, then T2 waits on T1 for the B lock, then T1 waits
for T2 on the A lock when it goes to commit.

> And, do these locks cascade?  If I choose to do an update on table A,
> and it has a foreign key to table B, which has a foreign key to table C,
> does the update-induced lock on A cause a lock on B /and/ C?

Not for checks since those don't change the table in question.  It's
possible for locks to cascade through referential action effects (although
that effect is partially minimized by the bug fix mentioned for
update unless the referencing column is itself the one being referenced)



Re: "deadlock detected" / cascading locks

From
Jan Wieck
Date:
Stephan Szabo wrote:> [...]

Yupp

>>And, do these locks cascade?  If I choose to do an update on table A,
>>and it has a foreign key to table B, which has a foreign key to table C,
>>does the update-induced lock on A cause a lock on B /and/ C?
> 
> 
> Not for checks since those don't change the table in question.  It's
> possible for locks to cascade through referential action effects (although
> that effect is partially minimized by the bug fix mentioned for
> update unless the referencing column is itself the one being referenced)

Normally referential actions like ON DELETE CASCADE will cascade top
town, parent->child->grandchild. If an update to table A cascades
through a referential integrity constraint into an update to table B,
there is no possible deadlock through this action by itself. The primary
key colum(s) in A being updated must have a UNIQUE constraint (as per
SQL standard). Having a lock for that column(s) in A means (logically in
this context) having a lock on all referencing rows in B. So noone else
can attempt to update these rows "through this constraints referential
action".

The other way around there can be multiple path's upward from many 
tables to common RI ancestors. But the checks done do not cascade up 
since they only lock for update. With my patch they don't even do that 
"if the referencing columns did not change.


Jan

-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #