1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Backport of:

----------------------------------------------------------
revno: 2617.69.2
committer: Konstantin Osipov <kostja@sun.com>
branch nick: 5.4-azalea-bugfixing
timestamp: Mon 2009-08-03 19:26:04 +0400
message:
  A fix and a test case for Bug#45035 "Altering table under LOCK TABLES
  results in "Error 1213 Deadlock found...".

  If a user had a table locked with LOCK TABLES
  for READ and for WRITE in the same connection, ALTER TABLE
  could fail.

  Root cause analysis:

  If a connection issues

  LOCK TABLE t1 write, t1 a read, t1 b read;

  the new LOCK TABLES code in 6.0 (part of WL 3726) will create
  the following list of TABLE_LIST objects
  (thd->locked_tables_list->m_locked_tables):

  {"t1" "b" tl_read_no_insert}, {"t1" "a" tl_read_no_insert},
  {"t1" "t1" tl_write }

  Later on, when we try to ALTER table t1, mysql_alter_table()
  closes all TABLE instances and releases its thr_lock locks,
  keeping only an exclusive metadata lock on t1.

  But when ALTER is finished, Locked_table_list::reopen_tables()
  tries to restore the original list of open and locked tables.

  Before this patch, it used to do so one by one:
  Open t1 b, get TL_READ_NO_INSERT lock,
  Open t1 a, get TL_READ_NO_INSERT lock
  Open t1, try to get TL_WRITE lock, deadlock.

  The cause of the deadlock is that thr_lock.c doesn't
  resolve the situation when the read list only consists
  of locks taken by the same thread, followed by this very
  thread trying to take a WRITE lock. Indeed, since
  thr_lock_multi always gets a sorted list of locks,
  WRITE locks always precede READ locks in the list
  to lock.

  Don't try to fix thr_lock.c deficiency, keep this
  code simple.
  Instead, try to take all thr_lock locks at once
  in ::reopen_tables().
This commit is contained in:
Konstantin Osipov
2009-12-08 11:38:45 +03:00
parent b4677ef084
commit 4a8a1c568d
5 changed files with 178 additions and 25 deletions

View File

@ -4515,7 +4515,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
}
end:
thd->locked_tables_list.unlink_all_closed_tables();
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
if (table == &tmp_table)
{
pthread_mutex_lock(&LOCK_open);
@ -7597,7 +7597,7 @@ err_with_mdl:
remove all references to the altered table from the list of locked
tables and release the exclusive metadata lock.
*/
thd->locked_tables_list.unlink_all_closed_tables();
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
if (target_mdl_request)
{
thd->mdl_context.release_lock(target_mdl_request->ticket);