MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:September 17 2009 7:31am
Subject:bzr commit into mysql-6.0-bugfixing branch (jon.hauglid:2822) Bug#46654
View as plain text  
#At file:///export/home/z/mysql-6.0-codebase-bugfixing-bug46654/ based on revid:dlenev@stripped

 2822 Jon Olav Hauglid	2009-09-17
      Bug #46654 False deadlock on concurrent DML/DDL with partitions, 
                 inconsistent behavior
      
      This is a preliminary version of the patch.
      
      The problem was that if one connection is running a multi-statement transaction 
      which involves a single partitioned table, and another connection attempts to 
      alter the table, the first connection gets ER_LOCK_DEADLOCK and cannot proceed 
      anymore, even when the ALTER TABLE statement in another connection is timed out 
      (which happens after innodb_lock_wait_timeout seconds).
      
      The reason for this was that the prepare phase for ALTER TABLE for partitioned
      tables removed the table from the table definition cache before it started
      waiting on the lock. The transaction running in the first connection would
      notice this and report ER_LOCK_DEADLOCK. The removal was unnecessary as it
      also is done at a later point when the lock has been taken.
      
      This patch changes the ALTER TABLE code so that tdc_remove_table() is only 
      called when the prepare phase fails.
      
      Test case added in bug46654.test. The test will be merged into an existing
      file before the final commit/push.

    added:
      mysql-test/r/bug46654.result
      mysql-test/t/bug46654-master.opt
      mysql-test/t/bug46654.test
    modified:
      sql/sql_partition.cc
      sql/sql_table.cc
=== added file 'mysql-test/r/bug46654.result'
--- a/mysql-test/r/bug46654.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/bug46654.result	2009-09-17 07:31:09 +0000
@@ -0,0 +1,31 @@
+#
+# Bug #46654 False deadlock on concurrent DML/DDL 
+#            with partitions, inconsistent behavior
+#
+DROP TABLE IF EXISTS tbl_with_partitions;
+CREATE TABLE tbl_with_partitions ( i INT ) 
+ENGINE = InnoDB
+PARTITION BY HASH(i);
+# Connection 1
+# Insert with disabled autocommit
+SET AUTOCOMMIT = 0;
+INSERT INTO tbl_with_partitions VALUES (1);
+# Connection 2
+# Alter table, waits for lock
+ALTER TABLE tbl_with_partitions ADD COLUMN f INT;
+# Connection 1
+# Test 1: Insert while Alter table is waiting.
+INSERT INTO tbl_with_partitions VALUES (2);
+# Connection 2
+# Wait until Alter table times out
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+# Connection 1
+# Test 2: Insert after Alter table has timed out
+INSERT INTO tbl_with_partitions VALUES (3);
+# Connection 2
+# Test 3: Another Alter table, should wait and timeout.
+ALTER TABLE tbl_with_partitions ADD COLUMN f INT;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+# Connection 1
+# Cleanup
+DROP TABLE tbl_with_partitions;

=== added file 'mysql-test/t/bug46654-master.opt'
--- a/mysql-test/t/bug46654-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/bug46654-master.opt	2009-09-17 07:31:09 +0000
@@ -0,0 +1 @@
+--innodb_lock_wait_timeout=2

=== added file 'mysql-test/t/bug46654.test'
--- a/mysql-test/t/bug46654.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/bug46654.test	2009-09-17 07:31:09 +0000
@@ -0,0 +1,66 @@
+--source include/have_innodb.inc
+--source include/have_partition.inc
+# Save the initial number of concurrent sessions.
+--source include/count_sessions.inc
+
+--echo #
+--echo # Bug #46654 False deadlock on concurrent DML/DDL 
+--echo #            with partitions, inconsistent behavior
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS tbl_with_partitions;
+--enable_warnings
+
+CREATE TABLE tbl_with_partitions ( i INT ) 
+	ENGINE = InnoDB
+	PARTITION BY HASH(i);
+
+connect(ddl,localhost,root);
+
+--echo # Connection 1
+--echo # Insert with disabled autocommit
+connection default;
+SET AUTOCOMMIT = 0;
+INSERT INTO tbl_with_partitions VALUES (1);
+
+--echo # Connection 2
+--echo # Alter table, waits for lock
+connection ddl;
+--send ALTER TABLE tbl_with_partitions ADD COLUMN f INT
+
+--echo # Connection 1
+--echo # Test 1: Insert while Alter table is waiting.
+connection default;
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+                       WHERE state= 'copy to tmp table' and
+                       INFO='ALTER TABLE tbl_with_partitions ADD COLUMN f INT';
+--source include/wait_condition.inc
+INSERT INTO tbl_with_partitions VALUES (2);
+
+--echo # Connection 2
+--echo # Wait until Alter table times out
+connection ddl;
+--error ER_LOCK_WAIT_TIMEOUT
+--reap
+
+--echo # Connection 1
+--echo # Test 2: Insert after Alter table has timed out
+connection default;
+INSERT INTO tbl_with_partitions VALUES (3);
+
+--echo # Connection 2
+--echo # Test 3: Another Alter table, should wait and timeout.
+connection ddl;
+--error ER_LOCK_WAIT_TIMEOUT
+ALTER TABLE tbl_with_partitions ADD COLUMN f INT;
+
+--echo # Connection 1
+--echo # Cleanup
+connection default;
+disconnect ddl;
+DROP TABLE tbl_with_partitions;
+
+# 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_partition.cc'
--- a/sql/sql_partition.cc	2009-09-11 10:45:04 +0000
+++ b/sql/sql_partition.cc	2009-09-17 07:31:09 +0000
@@ -3932,15 +3932,9 @@ bool mysql_unpack_partition(THD *thd,
       We need to free any memory objects allocated on item_free_list
       by the parser since we are keeping the old info from the first
       parser call in CREATE TABLE.
-      We'll ensure that this object isn't put into table cache also
-      just to ensure we don't get into strange situations with the
-      item objects.
     */
     thd->free_items();
     part_info= thd->work_part_info;
-    tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
-                      table->s->db.str,
-                      table->s->table_name.str);
     *work_part_info_used= true;
   }
   table->part_info= part_info;
@@ -4231,20 +4225,6 @@ uint prep_alter_part_table(THD *thd, TAB
 {
   DBUG_ENTER("prep_alter_part_table");
 
-  /*
-    We are going to manipulate the partition info on the table object
-    so we need to ensure that the table instances cached and all other
-    instances are properly closed.
-  */
-  if (table->part_info)
-  {
-    pthread_mutex_lock(&LOCK_open);
-    tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
-                     table->s->db.str,
-                     table->s->table_name.str);
-    pthread_mutex_unlock(&LOCK_open);
-  }
-
   thd->work_part_info= thd->lex->part_info;
   if (thd->work_part_info &&
       !(thd->work_part_info= thd->lex->part_info->get_clone()))

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-09-16 15:43:00 +0000
+++ b/sql/sql_table.cc	2009-09-17 07:31:09 +0000
@@ -7195,6 +7195,18 @@ view_err:
   if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
                             &partition_changed, &fast_alter_partition))
   {
+    /*
+       If prepare fails, remove the table object as it may have been
+       changed before prepare failed.
+    */
+    if (table->part_info)
+    {
+      pthread_mutex_lock(&LOCK_open);
+      tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
+                       table->s->db.str,
+                     table->s->table_name.str);
+      pthread_mutex_unlock(&LOCK_open);
+    }
     goto err;
   }
 #endif


Attachment: [text/bzr-bundle] bzr/jon.hauglid@sun.com-20090917073109-9ssv8dntkwg5g2aq.bundle
Thread
bzr commit into mysql-6.0-bugfixing branch (jon.hauglid:2822) Bug#46654Jon Olav Hauglid17 Sep
  • Re: bzr commit into mysql-6.0-bugfixing branch (jon.hauglid:2822)Bug#46654Konstantin Osipov18 Sep