Joe,

----- Original Message -----
From: "Joe Shear" <[EMAIL PROTECTED]>
Newsgroups: mailing.database.mysql
Sent: Wednesday, August 28, 2002 12:15 AM
Subject: Innodb deadlock printouts in .52


> Hi,
> I'm running mysql 3.23.52 w/ innodb tables, and I started getting some
> deadlocks since upgrading from .51.  When I do a show innodb status in
> prints out the following:
>
> 020826 19:22:15  LATEST DETECTED DEADLOCK:
> *** (1) TRANSACTION:
> TRANSACTION 0 16655549, ACTIVE 1 sec, OS thread id 87339022 inserting
> LOCK WAIT 6 lock struct(s), heap size 1024, undo log entries 4
> MySQL thread id 21314, query id 7772397 10.1.0.1 10.1.0.2 pas update
> INSERT plx_contact_field (user_id, entry_id, field_id, value) values (8,
> 0, 0, "name107788")
> *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
> RECORD LOCKS space id 0 page no 540698 n bits 272 table
> user/plx_contact_field index PRIMARY trx id 0 16655549 lock_mode X
> waiting
> Record lock, heap no 1
> *** (2) TRANSACTION:
> TRANSACTION 0 16655527, ACTIVE 2 sec, OS thread id 87326732 inserting
> 9 lock struct(s), heap size 1024, undo log entries 5
> MySQL thread id 21311, query id 7772401 10.1.0.1 10.1.0.2 pas update
> INSERT plx_contact_field (user_id, entry_id, field_id, value) values (7,
> 1983, 2, "pubemail1-1958")
> *** (2) HOLDS THE LOCK(S):
> RECORD LOCKS space id 0 page no 540698 n bits 272 table
> user/plx_contact_field index PRIMARY trx id 0 16655527 lock_mode X
> Record lock, heap no 1
> *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
> RECORD LOCKS space id 0 page no 540698 n bits 272 table
> user/plx_contact_field index PRIMARY trx id 0 16655527 lock_mode X
> waiting
> Record lock, heap no 1
> *** WE ROLL BACK TRANSACTION (2)
>
> It seems from the printout, that's what happening is that transaction 2
> obtains a lock on a row, then tries to obtain it again, while
> transaction 1 is waiting for that lock, and this causes a deadlock to be
> detected.  Is this the expected behavior?  We are running in
> serializable.  I would think that transaction 2 should first check to
> see if it already has the lock before it runs through and detects a
> deadlock.

have transactions (1) and (2) been reading the place where they are going to
insert? If yes, and you run in the SERIALIZABLE mode, then you will very
easily get a deadlock because they hold next-key locks over the insertion
spot.

If they have NOT read, updated, or deleted there, then the deadlock is
probably removed in MySQL-4.0.3 which should be out this week.

In the printout above a locking read, update, or delete may have set
next-key locks on the page 'supremum' (highest) record. The inserts had to
wait. To wait they set 'gap' type X-locks on the supremum.

A gap type lock does not grant the right to insert, it is above used as a
technical trick to leave the insert waiting. That is why (2) ignores the
X-lock it already has on the supremum record.

In InnoDB-3.23.52 the insert lock check was coarse: any waiting insert lock
on the same gap caused another insert to wait. In 4.0.3 this has been
improved. In 4.0.3 we have 4 types of locks on records:

1) ordinary next-key locks which lock the record and the gap before it;
2) gap locks only lock the gap before a record, not the record itself;
different transactions can have conflicting locks on the gap at the same
time, because when purge removes records, we may have to merge different
gaps; gap locks are purely inhibitive, they are used to force other users to
wait;
3) insert intention locks;
4) 'implicit' locks: every inserted record is X-locked by the inserting
transaction.

An insert in 4.0.3 only waits for type 1 and 2 locks to be released.

The details of next-key locking are complex. That is why they have not been
documented in the manual. The manual will be improved in the future to help
users to interpret the printout of SHOW INNODB STATUS.

See also http://www.innodb.com/ibman.html#Cope_with_deadlocks.

A relevant function from the source of 4.0.3:

/*************************************************************************
Checks if a lock request for a new lock has to wait for request lock2. */
UNIV_INLINE
ibool
lock_rec_has_to_wait(
/*=================*/
   /* out: TRUE if new lock has to wait for lock2 to be
   removed */
 trx_t* trx, /* in: trx of new lock */
 ulint mode, /* in: LOCK_S or LOCK_X */
 ulint gap, /* in: LOCK_GAP or 0 */
 ulint insert_intention,
   /* in: LOCK_INSERT_INTENTION or 0 */
 lock_t* lock2) /* in: another record lock; NOTE that it is assumed
   that this has a lock bit set on the same record as
   in lock1 */
{
 ut_ad(trx && lock2);
 ut_ad(lock_get_type(lock2) == LOCK_REC);
 ut_ad(mode == LOCK_S || mode == LOCK_X);
 ut_ad(gap == LOCK_GAP || gap == 0);
 ut_ad(insert_intention == LOCK_INSERT_INTENTION
           || insert_intention == 0);

 if (trx != lock2->trx && !lock_mode_compatible(mode,
           lock_get_mode(lock2))) {

  /* We have somewhat complex rules when gap type
  record locks cause waits */

  if (!gap && lock_rec_get_insert_intention(lock2)) {

   /* Request of a full next-key record does not
   need to wait for an insert intention lock to be
   removed. This is ok since our rules allow conflicting
   locks on gaps. This eliminates a spurious deadlock
   caused by a next-key lock waiting for an insert
   intention lock; when the insert intention lock was
   granted, the insert deadlocked on the waiting
   next-key lock. */

   return(FALSE);
  }

  if (insert_intention && lock_rec_get_insert_intention(lock2)) {

   /* An insert intention is not disturbed by another
   insert intention; this removes a spurious deadlock
   caused by inserts which had to wait for a next-key
   lock to be removed */

   return(FALSE);
  }

  return(TRUE);
 }

 return(FALSE);
}


> thanks for your help,
> Joe

Best regards,

Heikki Tuuri
Innobase Oy
---
InnoDB - transactions, row level locking, and foreign key support for MySQL
See http://www.innodb.com, download MySQL-Max from http://www.mysql.com



---------------------------------------------------------------------
Before posting, please check:
   http://www.mysql.com/manual.php   (the manual)
   http://lists.mysql.com/           (the list archive)

To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php

Reply via email to