• Konstantin Osipov's avatar
    Backport of: · 478e0960
    Konstantin Osipov authored
    ----------------------------------------------------------
    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().
    
    
    mysql-test/r/lock.result:
      Update results: test case for Bug#45035.
    mysql-test/t/lock.test:
      Add a test case for Bug#45035.
    sql/sql_base.cc:
      Take all thr_lock locks at once in Locked_tables_list::reopen_tables().
    sql/sql_class.h:
      Add a helper array to store tables for mysql_lock_tables()
      in reopen_tables().
    sql/sql_table.cc:
      Update unlink_all_closed_tables() to the new signature.
    478e0960
sql_table.cc 253 KB