MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:December 9 2009 9:44am
Subject:bzr commit into mysql-5.6-next-mr branch (kostja:3012) Bug#46748
View as plain text  
#At file:///opt/local/work/next-4284/ based on revid:kostja@stripped

 3012 Konstantin Osipov	2009-12-09
      Backport of:
      ------------------------------------------------------------
      revno: 2617.69.37
      committer: Dmitry Lenev <dlenev@stripped>
      branch nick: mysql-next-bg46748
      timestamp: Fri 2009-08-21 18:17:02 +0400
      message:
        Fix for bug #46748 "Assertion in MDL_context::wait_for_locks()
        on INSERT + CREATE TRIGGER".
      
        Concurrent execution of statements involving stored functions or triggers
        which were using several tables and DDL statements which affected those
        tables on debug build of server might have led to assertion failures in
        MDL_context::wait_for_locks(). Non-debug build was not affected.
      
        The problem was that during back-off which happens when open_tables()
        encounters conflicting metadata lock for one of the tables being open
        we didn't reset MDL_request::ticket value for requests which correspond
        to tables from extended prelocking set. Since these requests are part
        of of list of requests to be waited for in Open_table_context this broke
        assumption that ticket value for them is 0 in MDL_context::wait_for_locks()
        and caused assertion failure.
      
        This fix ensures that close_tables_for_reopen(), which performs this back-off
        resets MDL_request::ticket value not only for tables directly used by the
        statement but also for tables from extended prelocking set, thus satisfying
        assumption described above.
     @ mysql-test/r/mdl_sync.result
        Added test case for bug #46748 "Assertion in MDL_context::wait_for_locks()
        on INSERT + CREATE TRIGGER".
     @ mysql-test/t/mdl_sync.test
        Added test case for bug #46748 "Assertion in MDL_context::wait_for_locks()
        on INSERT + CREATE TRIGGER".
     @ sql/sql_base.cc
        Since metadata lock requests for tables from extended part of prelocking
        set are also part of list of requests to be waited for in Open_table_context
        in close_tables_for_reopen() we have to reset MDL_request::ticket 
        values for them to assumptions in MDL_context::wait_for_locks().

    modified:
      mysql-test/r/mdl_sync.result
      mysql-test/t/mdl_sync.test
      sql/sql_base.cc
=== modified file 'mysql-test/r/mdl_sync.result'
--- a/mysql-test/r/mdl_sync.result	2009-12-03 23:29:40 +0000
+++ b/mysql-test/r/mdl_sync.result	2009-12-09 09:44:05 +0000
@@ -19,3 +19,46 @@ connection: con2
 ERROR 42S02: Unknown table 't1'
 drop table t3;
 SET DEBUG_SYNC= 'RESET';
+#
+# Test for bug #46748 "Assertion in MDL_context::wait_for_locks()
+# on INSERT + CREATE TRIGGER".
+#
+drop tables if exists t1, t2, t3, t4, t5;
+# Let us simulate scenario in which we open some tables from extended
+# part of prelocking set but then encounter conflicting metadata lock,
+# so have to back-off and wait for it to go away.
+create table t1 (i int);
+create table t2 (j int);
+create table t3 (k int);
+create table t4 (l int);
+create trigger t1_bi before insert on t1 for each row
+insert into t2 values (new.i);
+create trigger t2_bi before insert on t2 for each row
+insert into t3 values (new.j);
+#
+# Switching to connection 'con1root'.
+lock tables t4 read;
+#
+# Switching to connection 'con2root'.
+# Send :
+rename table t3 to t5, t4 to t3;;
+#
+# Switching to connection 'default'.
+# Wait until the above RENAME TABLE adds pending requests for exclusive
+# metadata lock on its tables and blocks due to 't4' being used by LOCK
+# TABLES.
+# Send :
+insert into t1 values (1);;
+#
+# Switching to connection 'con1root'.
+# Wait until INSERT statement waits due to encountering pending
+# exclusive metadata lock on 't3'.
+unlock tables;
+#
+# Switching to connection 'con2root'.
+# Reap RENAME TABLE.
+#
+# Switching to connection 'default'.
+# Reap INSERT.
+# Clean-up.
+drop tables t1, t2, t3, t5;

=== modified file 'mysql-test/t/mdl_sync.test'
--- a/mysql-test/t/mdl_sync.test	2009-12-03 23:29:40 +0000
+++ b/mysql-test/t/mdl_sync.test	2009-12-09 09:44:05 +0000
@@ -3,6 +3,10 @@
 #
 --source include/have_debug_sync.inc
 
+# Save the initial number of concurrent sessions.
+--source include/count_sessions.inc
+
+
 # Clean up resources used in this test case.
 --disable_warnings
 SET DEBUG_SYNC= 'RESET';
@@ -67,3 +71,76 @@ disconnect con3;
 --disable_warnings
 SET DEBUG_SYNC= 'RESET';
 --enable_warnings
+
+
+--echo #
+--echo # Test for bug #46748 "Assertion in MDL_context::wait_for_locks()
+--echo # on INSERT + CREATE TRIGGER".
+--echo #
+--disable_warnings
+drop tables if exists t1, t2, t3, t4, t5;
+--enable_warnings
+--echo # Let us simulate scenario in which we open some tables from extended
+--echo # part of prelocking set but then encounter conflicting metadata lock,
+--echo # so have to back-off and wait for it to go away.
+connect (con1root,localhost,root,,test,,);
+connect (con2root,localhost,root,,test,,);
+connection default;
+create table t1 (i int);
+create table t2 (j int);
+create table t3 (k int);
+create table t4 (l int);
+create trigger t1_bi before insert on t1 for each row
+  insert into t2 values (new.i);
+create trigger t2_bi before insert on t2 for each row
+  insert into t3 values (new.j);
+--echo #
+--echo # Switching to connection 'con1root'.
+connection con1root;
+lock tables t4 read;
+--echo #
+--echo # Switching to connection 'con2root'.
+connection con2root;
+--echo # Send :
+--send rename table t3 to t5, t4 to t3;
+--echo #
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Wait until the above RENAME TABLE adds pending requests for exclusive
+--echo # metadata lock on its tables and blocks due to 't4' being used by LOCK
+--echo # TABLES.
+let $wait_condition= select count(*)= 1 from information_schema.processlist
+                       where state= 'Waiting for table' and
+                             info='rename table t3 to t5, t4 to t3';
+--source include/wait_condition.inc
+--echo # Send :
+--send insert into t1 values (1);
+--echo #
+--echo # Switching to connection 'con1root'.
+connection con1root;
+--echo # Wait until INSERT statement waits due to encountering pending
+--echo # exclusive metadata lock on 't3'.
+let $wait_condition= select count(*)= 1 from information_schema.processlist
+                       where state= 'Waiting for table' and
+                             info='insert into t1 values (1)';
+--source include/wait_condition.inc
+unlock tables;
+--echo #
+--echo # Switching to connection 'con2root'.
+connection con2root;
+--echo # Reap RENAME TABLE.
+--reap
+--echo #
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Reap INSERT.
+--reap
+--echo # Clean-up.
+disconnect con1root;
+disconnect con2root;
+drop tables t1, t2, t3, t5;
+
+
+# Check that all connections opened by test cases in this file are really
+# gone so execution of other tests won't be affected by their presence.
+--source include/wait_until_count_sessions.inc

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-12-09 09:04:55 +0000
+++ b/sql/sql_base.cc	2009-12-09 09:44:05 +0000
@@ -5104,19 +5104,31 @@ bool lock_tables(THD *thd, TABLE_LIST *t
 
 void close_tables_for_reopen(THD *thd, TABLE_LIST **tables)
 {
+  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
+  TABLE_LIST *tmp;
+
   /*
     If table list consists only from tables from prelocking set, table list
     for new attempt should be empty, so we have to update list's root pointer.
   */
-  if (thd->lex->first_not_own_table() == *tables)
+  if (first_not_own_table == *tables)
     *tables= 0;
   thd->lex->chop_off_not_own_tables();
   sp_remove_not_own_routines(thd->lex);
-  for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
+  for (tmp= *tables; tmp; tmp= tmp->next_global)
   {
     tmp->table= 0;
     tmp->mdl_request.ticket= NULL;
   }
+  /*
+    Metadata lock requests for tables from extended part of prelocking set
+    are part of list of requests to be waited for in Open_table_context.
+    So to satisfy assumptions in MDL_context::wait_for_locks(), which will
+    performs the waiting, we have to reset MDL_request::ticket values for
+    them as well.
+  */
+  for (tmp= first_not_own_table; tmp; tmp= tmp->next_global)
+    tmp->mdl_request.ticket= NULL;
   close_thread_tables(thd);
   if (!thd->locked_tables_mode)
     thd->mdl_context.release_all_locks();


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091209094405-lt6tpg6yjxmmyaiu.bundle
Thread
bzr commit into mysql-5.6-next-mr branch (kostja:3012) Bug#46748Konstantin Osipov9 Dec