From: Date: October 3 2007 1:16pm Subject: Re: bk commit into 5.2 tree (davi:1.2609) BUG#25858 List-Archive: http://lists.mysql.com/commits/34824 Message-Id: <20071003111629.GE2101@bodhi> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii * Davi Arnaut [07/10/03 04:45]: > ChangeSet@stripped, 2007-10-02 21:27:31-03:00, davi@stripped +21 -0 > Bug#25858 Some DROP TABLE under LOCK TABLES can cause deadlocks > > When a client (connection) holds a lock on a table and attempts to > drop (obtain a exclusive lock) on a second table that is already held > by a second client and the second client then attempts to drop the table > that is held by the first client, leads to a circular wait deadlock. This > scenario is very similar to trying to drop (or rename) a table while > holding read locks and are correctly forbidden. > > The solution is to allow a drop table operation to continue only if the > table being dropped is write (exclusively) locked, or if the table is > temporary, or if the client is not holding any locks. Using this scheme > prevents the creation of a circular chain in which each client is waiting > for one table that the next client in the chain is holding. > > This is incompatible change, as can be seen by number of tests cases > that needed to be fixed, but is consistent with respect to behavior of > the different scenarios in which the circular wait might happen. OK to push. > diff -Nrup a/sql/lock.cc b/sql/lock.cc > --- a/sql/lock.cc 2007-09-27 16:56:21 -03:00 > +++ b/sql/lock.cc 2007-10-02 21:27:23 -03:00 > @@ -1002,6 +1002,7 @@ int lock_table_name(THD *thd, TABLE_LIST > char key[MAX_DBKEY_LENGTH]; > char *db= table_list->db; > uint key_length; > + bool found_locked_table= FALSE; > HASH_SEARCH_STATE state; > DBUG_ENTER("lock_table_name"); > DBUG_PRINT("enter",("db: %s name: %s", db, table_list->table_name)); > @@ -1017,6 +1018,13 @@ int lock_table_name(THD *thd, TABLE_LIST > table = (TABLE*) hash_next(&open_cache,(uchar*) key, > key_length, &state)) > { > + if (table->reginfo.lock_type < TL_WRITE) > + { > + if (table->in_use == thd) > + found_locked_table= TRUE; > + continue; > + } > + > if (table->in_use == thd) > { > DBUG_PRINT("info", ("Table is in use")); > @@ -1025,6 +1033,17 @@ int lock_table_name(THD *thd, TABLE_LIST > DBUG_RETURN(0); > } > } > + } > + > + if (thd->locked_tables && thd->locked_tables->table_count && > + ! find_temporary_table(thd, table_list->db, table_list->table_name)) > + { > + if (found_locked_table) > + my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias); > + else > + my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_list->alias); > + > + DBUG_RETURN(-1); > } > > if (!(table= table_cache_insert_placeholder(thd, key, key_length))) -- -- Konstantin Osipov Software Developer, Moscow, Russia -- MySQL AB, www.mysql.com The best DATABASE COMPANY in the GALAXY