MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:December 10 2009 1:41pm
Subject:bzr push into mysql-5.6-next-mr branch (jon.hauglid:3025 to 3028) Bug#43867
View as plain text  
 3028 Jon Olav Hauglid	2009-12-10
      Backport of revno: 2617.80.1
      Also re-enables the test for Bug #43867
      
      Followup to Bug#46654 False deadlock on concurrent DML/DDL with partitions, 
                            inconsistent behavior
      
      Partition_sync.test uses features only available in debug builds.
      Disabling the test for non-debug builds.

    modified:
      mysql-test/r/partition_sync.result
      mysql-test/t/partition_sync.test
 3027 Jon Olav Hauglid	2009-12-10
      Backport of revno: 2617.68.37
      
      Bug #46654 False deadlock on concurrent DML/DDL with partitions, 
                 inconsistent behavior
      
      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 has timed out or failed.
      
      The reason for this was that the prepare phase for ALTER TABLE for 
      partitioned tables removed all instances of 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. 
      
      This patch changes the prep_alter_part_table() ALTER TABLE code so that 
      tdc_remove_table() is no longer called. Instead, only the TABLE instance
      changed by prep_alter_part_table() is marked as needing reopen.
      
      The patch also removes an unnecessary call to tdc_remove_table() from 
      mysql_unpack_partition() as the changed TABLE object is destroyed by the 
      caller at a later point.
      
      Test case added in partition_sync.test.

    modified:
      mysql-test/r/partition_sync.result
      mysql-test/t/partition_sync.test
      sql/sql_base.cc
      sql/sql_handler.cc
      sql/sql_insert.cc
      sql/sql_partition.cc
      sql/sql_table.cc
      sql/table.h
 3026 Jon Olav Hauglid	2009-12-10
      Backport of revno: 3514
      
      Bug#40181 Made use of tdc_remove_table instead of just 
      setting share->version to 0 to make sure all unused table
      instances go away as part of CREATE/ALTER TABLE.

    modified:
      mysql-test/r/partition.result
      mysql-test/t/partition.test
      sql/sql_partition.cc
 3025 Jon Olav Hauglid	2009-12-10
      Backport of revno: 3673
      
      Bug #47313 assert in check_key_in_view during CALL procedure
      
      View definitions are inlined in a stored procedure when the procedure
      is fist called. This means that if a temporary table is later added
      with the same name as the view, the stored procedure will still
      use the view. This happens even if temporary tables normally shadow
      base tables/views.
      
      The reason for the assert was that even if the stored procedure
      referenced the view, open_table() still tried to open the
      temporary table. This "half view/half temporary table" state
      caused the assert.
      
      The bug was not present in 5.1 as open_table() is not called
      for the view there. This code was changed with the introduction 
      of MDL in order to properly lock the view and any objects it 
      refers to.
      
      This patch fixes the problem by instructing open_table()
      to open base tables/views (using OT_BASE_ONLY) when reopening
      tables/views used by stored procedures. This also means that
      a prepared statement is no longer invalidated if a temporary
      table is created with the same name as a view used in the
      prepared statement.
      
      Test case added to sp.test. The test case also demonstrates
      the effect of sp cache invalidation between CALLs.
     @ mysql-test/t/ps_ddl.test
        Extended the VIEW->TEMPORARY TABLE transition test to cover not only
        merged views, but now also materialized views and views containing
        a reference to an information schema table. 
        
        Test also updated to reflect the change to prepared statement
        invalidatation.

    modified:
      mysql-test/r/ps_ddl.result
      mysql-test/r/sp.result
      mysql-test/t/ps_ddl.test
      mysql-test/t/sp.test
      sql/sql_view.cc
=== modified file 'mysql-test/r/partition.result'
--- a/mysql-test/r/partition.result	2009-11-25 18:49:30 +0000
+++ b/mysql-test/r/partition.result	2009-12-10 13:15:50 +0000
@@ -65,6 +65,15 @@ show indexes from t1;
 Table	Non_unique	Key_name	Seq_in_index	Column_name	Collation	Cardinality	Sub_part	Packed	Null	Index_type	Comment
 t1	1	a	1	a	A	1	NULL	NULL	YES	BTREE	
 drop table t1;
+create table t1 (a int)
+partition by hash (a);
+create index i on t1 (a);
+insert into t1 values (1);
+insert into t1 select * from t1;
+create index i on t1 (a);
+ERROR 42000: Duplicate key name 'i'
+create index i2 on t1 (a);
+drop table t1;
 CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a))
 ENGINE=MyISAM
 PARTITION BY HASH (a);

=== modified file 'mysql-test/r/partition_sync.result'
--- a/mysql-test/r/partition_sync.result	2009-12-04 23:02:48 +0000
+++ b/mysql-test/r/partition_sync.result	2009-12-10 13:41:41 +0000
@@ -1,2 +1,57 @@
-# Disabled until Bug#46654 False deadlock on concurrent DML/DDL 
-# with partitions, inconsistent behavior is backported
+#
+# Bug #43867 ALTER TABLE on a partitioned table 
+#            causes unnecessary deadlocks
+#
+CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (1),
+PARTITION p1 VALUES LESS THAN (2));
+INSERT INTO t1 VALUES (0),(1);
+# Connection 2
+BEGIN;
+SELECT * FROM t1;
+a
+0
+1
+# Connection 1
+ALTER TABLE t1 DROP PARTITION p3;
+ERROR HY000: Error in list of partitions to DROP
+# Connection 2
+# This failed with deadlock and should not do so.
+SELECT * FROM t1;
+a
+0
+1
+# Connection 1
+DROP TABLE t1;
+#
+# 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 ) 
+PARTITION BY HASH(i);
+INSERT INTO tbl_with_partitions VALUES (1);
+# Connection 3
+LOCK TABLE tbl_with_partitions READ;
+# Connection 1
+# Access table with disabled autocommit
+SET AUTOCOMMIT = 0;
+SELECT * FROM tbl_with_partitions;
+i
+1
+# Connection 2
+# Alter table, abort after prepare
+set session debug="+d,abort_copy_table";
+ALTER TABLE tbl_with_partitions ADD COLUMN f INT;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+# Connection 1
+# Try accessing the table after Alter aborted.
+# This used to give ER_LOCK_DEADLOCK.
+SELECT * FROM tbl_with_partitions;
+i
+1
+# Connection 3
+UNLOCK TABLES;
+# Connection 1
+# Cleanup
+DROP TABLE tbl_with_partitions;

=== modified file 'mysql-test/t/partition.test'
--- a/mysql-test/t/partition.test	2009-11-25 18:49:30 +0000
+++ b/mysql-test/t/partition.test	2009-12-10 13:15:50 +0000
@@ -75,6 +75,19 @@ show indexes from t1;
 drop table t1;
 
 #
+# Bug#40181: hang if create index
+#
+create table t1 (a int)
+partition by hash (a);
+create index i on t1 (a);
+insert into t1 values (1);
+insert into t1 select * from t1;
+--error ER_DUP_KEYNAME
+create index i on t1 (a);
+create index i2 on t1 (a);
+drop table t1;
+
+#
 # Bug#36001: Partitions: spelling and using some error messages
 #
 --error ER_FOREIGN_KEY_ON_PARTITIONED

=== modified file 'mysql-test/t/partition_sync.test'
--- a/mysql-test/t/partition_sync.test	2009-12-04 23:02:48 +0000
+++ b/mysql-test/t/partition_sync.test	2009-12-10 13:41:41 +0000
@@ -1,42 +1,91 @@
 --source include/have_partition.inc
+--source include/have_debug.inc
 # Save the initial number of concurrent sessions.
 --source include/count_sessions.inc
 
---echo # Disabled until Bug#46654 False deadlock on concurrent DML/DDL 
---echo # with partitions, inconsistent behavior is backported
+--echo #
+--echo # Bug #43867 ALTER TABLE on a partitioned table 
+--echo #            causes unnecessary deadlocks
+--echo #
 
-#--echo #
-#--echo # Bug #43867 ALTER TABLE on a partitioned table 
-#--echo #            causes unnecessary deadlocks
-#--echo #
-#
-#CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
-#(PARTITION p0 VALUES LESS THAN (1),
-# PARTITION p1 VALUES LESS THAN (2));
-#
-#INSERT INTO t1 VALUES (0),(1);
-#
-#connect(con1,localhost,root);
-#
-#--echo # Connection 2
-#connection con1;
-#BEGIN;
-#SELECT * FROM t1;
-#
-#--echo # Connection 1
-#connection default;
-#--error ER_DROP_PARTITION_NON_EXISTENT
-#ALTER TABLE t1 DROP PARTITION p3;
-#
-#--echo # Connection 2
-#connection con1;
-#--echo # This failed with deadlock and should not do so.
-#SELECT * FROM t1;
-#
-#--echo # Connection 1
-#connection default;
-#disconnect con1;
-#DROP TABLE t1;
+CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (1),
+ PARTITION p1 VALUES LESS THAN (2));
+
+INSERT INTO t1 VALUES (0),(1);
+
+connect(con1,localhost,root);
+
+--echo # Connection 2
+connection con1;
+BEGIN;
+SELECT * FROM t1;
+
+--echo # Connection 1
+connection default;
+--error ER_DROP_PARTITION_NON_EXISTENT
+ALTER TABLE t1 DROP PARTITION p3;
+
+--echo # Connection 2
+connection con1;
+--echo # This failed with deadlock and should not do so.
+SELECT * FROM t1;
+
+--echo # Connection 1
+connection default;
+disconnect con1;
+DROP TABLE t1;
+
+
+--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 ) 
+	PARTITION BY HASH(i);
+INSERT INTO tbl_with_partitions VALUES (1);
+
+connect(con2,localhost,root);
+connect(con3,localhost,root);
+
+--echo # Connection 3
+connection con3;
+LOCK TABLE tbl_with_partitions READ;
+
+--echo # Connection 1
+--echo # Access table with disabled autocommit
+connection default;
+SET AUTOCOMMIT = 0;
+SELECT * FROM tbl_with_partitions;
+
+--echo # Connection 2
+--echo # Alter table, abort after prepare
+connection con2;
+set session debug="+d,abort_copy_table";
+--error ER_LOCK_WAIT_TIMEOUT
+ALTER TABLE tbl_with_partitions ADD COLUMN f INT;
+
+--echo # Connection 1
+--echo # Try accessing the table after Alter aborted.
+--echo # This used to give ER_LOCK_DEADLOCK.
+connection default;
+SELECT * FROM tbl_with_partitions;
+
+--echo # Connection 3
+connection con3;
+UNLOCK TABLES;
+
+--echo # Connection 1
+--echo # Cleanup
+connection default;
+disconnect con2;
+disconnect con3;
+DROP TABLE tbl_with_partitions;
 
 
 # Check that all connections opened by test cases in this file are really

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-12-10 10:53:20 +0000
+++ b/sql/sql_base.cc	2009-12-10 13:26:00 +0000
@@ -1530,8 +1530,8 @@ bool close_thread_table(THD *thd, TABLE 
   *table_ptr=table->next;
 
   table->mdl_ticket= NULL;
-  if (table->needs_reopen() ||
-      thd->version != refresh_version || !table->db_stat ||
+  if (table->s->needs_reopen() ||
+      thd->version != refresh_version || table->needs_reopen() ||
       table_def_shutdown_in_progress)
   {
     free_cache_entry(table);
@@ -8186,13 +8186,13 @@ bool mysql_notify_thread_having_shared_l
        thd_table= thd_table->next)
   {
     /*
-      Check for TABLE::db_stat is needed since in some places we call
+      Check for TABLE::needs_reopen() is needed since in some places we call
       handler::close() for table instance (and set TABLE::db_stat to 0)
       and do not remove such instances from the THD::open_tables
       for some time, during which other thread can see those instances
       (e.g. see partitioning code).
     */
-    if (thd_table->db_stat)
+    if (!thd_table->needs_reopen())
       signalled|= mysql_lock_abort_for_thread(thd, thd_table);
   }
   pthread_mutex_unlock(&LOCK_open);

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2009-12-10 08:41:03 +0000
+++ b/sql/sql_handler.cc	2009-12-10 13:26:00 +0000
@@ -820,7 +820,7 @@ void mysql_ha_flush(THD *thd)
     if (hash_tables->table &&
         (hash_tables->table->mdl_ticket &&
          hash_tables->table->mdl_ticket->has_pending_conflicting_lock() ||
-         hash_tables->table->needs_reopen()))
+         hash_tables->table->s->needs_reopen()))
       mysql_ha_close_table(thd, hash_tables);
   }
 

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2009-12-10 10:53:20 +0000
+++ b/sql/sql_insert.cc	2009-12-10 13:26:00 +0000
@@ -2657,7 +2657,7 @@ bool Delayed_insert::handle_inserts(void
 
   thd_proc_info(&thd, "insert");
   max_rows= delayed_insert_limit;
-  if (thd.killed || table->needs_reopen())
+  if (thd.killed || table->s->needs_reopen())
   {
     thd.killed= THD::KILL_CONNECTION;
     max_rows= ULONG_MAX;                     // Do as much as possible

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2009-12-10 10:53:20 +0000
+++ b/sql/sql_partition.cc	2009-12-10 13:26:00 +0000
@@ -4183,13 +4183,13 @@ 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.
+
+      This table object can not be used any more. However, since
+      this is CREATE TABLE, we know that it will be destroyed by the
+      caller, and rely on that.
     */
     thd->free_items();
     part_info= thd->work_part_info;
-    table->s->version= 0UL;
     *work_part_info_used= true;
   }
   table->part_info= part_info;
@@ -4482,12 +4482,11 @@ uint prep_alter_part_table(THD *thd, TAB
 
   /*
     We are going to manipulate the partition info on the table object
-    so we need to ensure that the data structure of the table object
-    is freed by setting version to 0. table->s->version= 0 forces a
-    flush of the table object in close_thread_tables().
+    so we need to ensure that the table instance is removed from the
+    table cache.
   */
   if (table->part_info)
-    table->s->version= 0L;
+    table->m_needs_reopen= TRUE;
 
   thd->work_part_info= thd->lex->part_info;
   if (thd->work_part_info &&
@@ -6242,7 +6241,9 @@ static int alter_close_tables(ALTER_PART
         alter_partition_lock_handling() and the table is closed
         by close_thread_tables() instead.
       */
-      table->s->version= 0;
+      tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
+                       table->s->db.str,
+                       table->s->table_name.str);
     }
   }
   pthread_mutex_unlock(&LOCK_open);

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-12-10 10:53:20 +0000
+++ b/sql/sql_table.cc	2009-12-10 13:26:00 +0000
@@ -7049,6 +7049,10 @@ view_err:
     new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
     new_table->next_number_field=new_table->found_next_number_field;
     thd_proc_info(thd, "copy to tmp table");
+    DBUG_EXECUTE_IF("abort_copy_table", {
+        my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
+        goto err_new_table_cleanup;
+      });
     error= copy_data_between_tables(table, new_table,
                                     alter_info->create_list, ignore,
                                     order_num, order, &copied, &deleted,

=== modified file 'sql/table.h'
--- a/sql/table.h	2009-12-10 10:53:20 +0000
+++ b/sql/table.h	2009-12-10 13:26:00 +0000
@@ -294,6 +294,8 @@ TABLE_CATEGORY get_table_category(const 
 
 struct TABLE_share;
 
+extern ulong refresh_version;
+
 /*
   This structure is shared between different table objects. There is one
   instance of table share per one table in the database.
@@ -503,6 +505,14 @@ struct TABLE_SHARE
     return table_map_id;
   }
 
+
+  /*
+    Must all TABLEs be reopened?
+  */
+  inline bool needs_reopen()
+  {
+    return version != refresh_version;
+  }
   /**
     Convert unrelated members of TABLE_SHARE to one enum
     representing its type.
@@ -605,8 +615,6 @@ struct TABLE_SHARE
 };
 
 
-extern ulong refresh_version;
-
 /* Information for one open table */
 enum index_hint_type
 {
@@ -804,6 +812,7 @@ public:
   my_bool insert_or_update;             /* Can be used by the handler */
   my_bool alias_name_used;		/* true if table_name is alias */
   my_bool get_fields_in_item_tree;      /* Signal to fix_field */
+  my_bool m_needs_reopen;
 
   REGINFO reginfo;			/* field connections */
   MEM_ROOT mem_root;
@@ -853,7 +862,7 @@ public:
     Is this instance of the table should be reopen?
   */
   inline bool needs_reopen()
-  { return s->version != refresh_version; }
+  { return !db_stat || m_needs_reopen; }
 };
 
 


Attachment: [text/bzr-bundle] bzr/jon.hauglid@sun.com-20091210134141-48dn6oqenokprap8.bundle
Thread
bzr push into mysql-5.6-next-mr branch (jon.hauglid:3025 to 3028) Bug#43867Jon Olav Hauglid10 Dec