* Davi Arnaut <davi@stripped> [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