List:Commits« Previous MessageNext Message »
From:Alexey Kopytov Date:May 11 2010 2:16pm
Subject:bzr commit into mysql-trunk branch (Alexey.Kopytov:3019) Bug#50561
View as plain text  
#At file:///data/src/bzr/mysql-trunk-merge/ based on revid:alexey.kopytov@stripped

 3019 Alexey Kopytov	2010-05-11 [merge]
      Manual merge of the fix for bug#50561 to mysql-trunk-merge.
      
      Conflicts:
      
      Text conflict in sql/sql_base.cc
      Text conflict in sql/sql_partition.cc
      Text conflict in sql/sql_priv.h
      Text conflict in sql/sql_show.cc

    added:
      mysql-test/suite/parts/r/partition_debug_sync_innodb.result
      mysql-test/suite/parts/t/partition_debug_sync_innodb-master.opt
      mysql-test/suite/parts/t/partition_debug_sync_innodb.test
    modified:
      sql/authors.h
      sql/ha_partition.cc
      sql/sql_base.cc
      sql/sql_partition.cc
      sql/sql_show.cc
=== added file 'mysql-test/suite/parts/r/partition_debug_sync_innodb.result'
--- a/mysql-test/suite/parts/r/partition_debug_sync_innodb.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/parts/r/partition_debug_sync_innodb.result	2010-05-11 14:15:40 +0000
@@ -0,0 +1,61 @@
+#
+# Bug#50561: ALTER PARTITIONS does not have adequate lock, breaks with
+#            concurrent I_S query
+create table t1 (a int)
+engine = innodb
+partition by range (a)
+(partition p0 values less than MAXVALUE);
+insert into t1 values (1), (11), (21), (33);
+SELECT * FROM t1;
+a
+1
+11
+21
+33
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
+t1#P#p0.ibd
+t1.frm
+t1.par
+SET DEBUG_SYNC='before_open_in_get_all_tables SIGNAL parked WAIT_FOR open';
+SET DEBUG_SYNC='partition_open_error SIGNAL alter WAIT_FOR finish';
+SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
+SET DEBUG_SYNC = 'now WAIT_FOR parked';
+# When waiting for the name lock in get_all_tables in sql_show.cc
+# this will not be concurrent any more, thus the TIMEOUT
+SET DEBUG_SYNC = 'before_rename_partitions SIGNAL open WAIT_FOR alter TIMEOUT 1';
+# Needs to be executed twice, since first is this 'SET DEBUG_SYNC ...'
+SET DEBUG_SYNC = 'before_close_thread_tables SIGNAL finish EXECUTE 2';
+ALTER TABLE t1 REORGANIZE PARTITION p0 INTO
+(PARTITION p0 VALUES LESS THAN (10),
+PARTITION p10 VALUES LESS THAN MAXVALUE);
+Warnings:
+Warning	1639	debug sync point wait timed out
+TABLE_CATALOG	TABLE_SCHEMA	TABLE_NAME	PARTITION_NAME	SUBPARTITION_NAME	PARTITION_ORDINAL_POSITION	SUBPARTITION_ORDINAL_POSITION	PARTITION_METHOD	SUBPARTITION_METHOD	PARTITION_EXPRESSION	SUBPARTITION_EXPRESSION	PARTITION_DESCRIPTION	TABLE_ROWS	AVG_ROW_LENGTH	DATA_LENGTH	MAX_DATA_LENGTH	INDEX_LENGTH	DATA_FREE	CREATE_TIME	UPDATE_TIME	CHECK_TIME	CHECKSUM	PARTITION_COMMENT	NODEGROUP	TABLESPACE_NAME
+def	test	t1	p0	NULL	1	NULL	RANGE	NULL	a	NULL	10	1	16384	16384	NULL	0	0	NULL	NULL	NULL	NULL		default	NULL
+def	test	t1	p10	NULL	2	NULL	RANGE	NULL	a	NULL	MAXVALUE	3	5461	16384	NULL	0	0	NULL	NULL	NULL	NULL		default	NULL
+t1#P#p0.ibd
+t1#P#p10.ibd
+t1.frm
+t1.par
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (10) ENGINE = InnoDB,
+ PARTITION p10 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
+SELECT * FROM t1;
+a
+1
+11
+21
+33
+drop table t1;
+SET DEBUG_SYNC = 'RESET';

=== added file 'mysql-test/suite/parts/t/partition_debug_sync_innodb-master.opt'
--- a/mysql-test/suite/parts/t/partition_debug_sync_innodb-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/parts/t/partition_debug_sync_innodb-master.opt	2010-03-17 14:10:41 +0000
@@ -0,0 +1 @@
+--innodb_file_per_table=1

=== added file 'mysql-test/suite/parts/t/partition_debug_sync_innodb.test'
--- a/mysql-test/suite/parts/t/partition_debug_sync_innodb.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/parts/t/partition_debug_sync_innodb.test	2010-03-17 14:10:41 +0000
@@ -0,0 +1,44 @@
+--source include/have_innodb.inc
+--source include/have_partition.inc
+--source include/have_debug_sync.inc
+
+let $MYSQLD_DATADIR=`SELECT @@datadir`;
+
+--echo #
+--echo # Bug#50561: ALTER PARTITIONS does not have adequate lock, breaks with
+--echo #            concurrent I_S query
+create table t1 (a int)
+engine = innodb
+partition by range (a)
+(partition p0 values less than MAXVALUE);
+insert into t1 values (1), (11), (21), (33);
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+--list_files $MYSQLD_DATADIR/test
+
+SET DEBUG_SYNC='before_open_in_get_all_tables SIGNAL parked WAIT_FOR open';
+SET DEBUG_SYNC='partition_open_error SIGNAL alter WAIT_FOR finish';
+send
+SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
+
+connect (con1, localhost, root,,);
+SET DEBUG_SYNC = 'now WAIT_FOR parked';
+--echo # When waiting for the name lock in get_all_tables in sql_show.cc
+--echo # this will not be concurrent any more, thus the TIMEOUT
+SET DEBUG_SYNC = 'before_rename_partitions SIGNAL open WAIT_FOR alter TIMEOUT 1';
+--echo # Needs to be executed twice, since first is this 'SET DEBUG_SYNC ...'
+SET DEBUG_SYNC = 'before_close_thread_tables SIGNAL finish EXECUTE 2';
+--error 0,ER_TABLE_EXISTS_ERROR
+ALTER TABLE t1 REORGANIZE PARTITION p0 INTO
+(PARTITION p0 VALUES LESS THAN (10),
+ PARTITION p10 VALUES LESS THAN MAXVALUE);
+
+disconnect con1;
+connection default;
+--reap
+--list_files $MYSQLD_DATADIR/test
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+drop table t1;
+--list_files $MYSQLD_DATADIR/test
+SET DEBUG_SYNC = 'RESET';

=== modified file 'sql/authors.h'
--- a/sql/authors.h	2010-01-07 05:42:07 +0000
+++ b/sql/authors.h	2010-05-11 14:15:40 +0000
@@ -80,6 +80,7 @@ struct show_table_authors_st show_table_
   { "Eric Herman", "Amsterdam, Netherlands", "Bug fixing - federated" },
   { "Andrey Hristov", "Walldorf, Germany", "Event scheduler (5.1)" },
   { "Alexander (Alexi) Ivanov", "St. Petersburg, Russia", "Replication" },
+  { "Mattias Jonsson", "Uppsala, Sweden", "Partitioning" },
   { "Alexander (Salle) Keremidarski", "Sofia, Bulgaria",
     "Bug fixing" },
   { "Mats Kindahl", "Storvreta, Sweden", "Replication" },

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2010-04-29 20:33:06 +0000
+++ b/sql/ha_partition.cc	2010-05-11 14:15:40 +0000
@@ -60,6 +60,8 @@
 #include "key.h"
 #include "sql_plugin.h"
 
+#include "debug_sync.h"
+
 static const char *ha_par_ext= ".par";
 #ifdef NOT_USED
 static int free_share(PARTITION_SHARE * share);
@@ -692,6 +694,7 @@ int ha_partition::rename_partitions(cons
   DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path,
                                                    norm_name_buff)));
 
+  DEBUG_SYNC(ha_thd(), "before_rename_partitions");
   if (temp_partitions)
   {
     /*
@@ -2684,6 +2687,7 @@ int ha_partition::open(const char *name,
   DBUG_RETURN(0);
 
 err_handler:
+  DEBUG_SYNC(ha_thd(), "partition_open_error");
   while (file-- != m_file)
     (*file)->close();
   bitmap_free(&m_bulk_insert_started);

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-05-11 08:25:33 +0000
+++ b/sql/sql_base.cc	2010-05-11 14:15:40 +0000
@@ -1418,6 +1418,12 @@ void close_thread_tables(THD *thd)
                           table->s->table_name.str, (long) table));
 #endif
 
+#if defined(ENABLED_DEBUG_SYNC)
+  /* debug_sync may not be initialized for some slave threads */
+  if (thd->debug_sync_control)
+    DEBUG_SYNC(thd, "before_close_thread_tables");
+#endif
+
   /* Detach MERGE children after every statement. Even under LOCK TABLES. */
   for (table= thd->open_tables; table; table= table->next)
   {
@@ -5242,8 +5248,8 @@ bool open_and_lock_tables(THD *thd, TABL
     thd		- thread handler
     tables	- list of tables for open
     flags       - bitmap of flags to modify how the tables will be open:
-                  MYSQL_OPEN_IGNORE_FLUSH - open table even if someone has
-                  done a flush or namelock on it.
+                  MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
+                  done a flush on it.
 
   RETURN
     FALSE - ok
@@ -8782,8 +8788,57 @@ bool is_equal(const LEX_STRING *a, const
 
 
 /*
+  Unlock and close table before renaming and dropping partitions
   SYNOPSIS
-    abort_and_upgrade_lock()
+    alter_close_tables()
+    lpt                        Struct carrying parameters
+  RETURN VALUES
+    0
+*/
+
+static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+  TABLE_SHARE *share= lpt->table->s;
+  THD *thd= lpt->thd;
+  TABLE *table;
+  DBUG_ENTER("alter_close_tables");
+  /*
+    We must keep LOCK_open while manipulating with thd->open_tables.
+    Another thread may be working on it.
+  */
+  mysql_mutex_lock(&LOCK_open);
+  /*
+    We can safely remove locks for all tables with the same name:
+    later they will all be closed anyway in
+    alter_partition_lock_handling().
+  */
+  for (table= thd->open_tables; table ; table= table->next)
+  {
+    if (!strcmp(table->s->table_name.str, share->table_name.str) &&
+	!strcmp(table->s->db.str, share->db.str))
+    {
+      mysql_lock_remove(thd, thd->lock, table);
+      table->file->close();
+      table->db_stat= 0;                        // Mark file closed
+      /*
+        Ensure that we won't end up with a crippled table instance
+        in the table cache if an error occurs before we reach
+        alter_partition_lock_handling() and the table is closed
+        by close_thread_tables() instead.
+      */
+      tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
+                       table->s->db.str,
+                       table->s->table_name.str);
+    }
+  }
+  mysql_mutex_unlock(&LOCK_open);
+  DBUG_RETURN(0);
+}
+
+
+/*
+  SYNOPSIS
+    abort_and_upgrade_lock_and_close_table()
     lpt                           Parameter passing struct
     All parameters passed through the ALTER_PARTITION_PARAM_TYPE object
   RETURN VALUE
@@ -8792,7 +8847,7 @@ bool is_equal(const LEX_STRING *a, const
     Remember old lock level (for possible downgrade later on), abort all
     waiting threads and ensure that all keeping locks currently are
     completed such that we own the lock exclusively and no other interaction
-    is ongoing.
+    is ongoing. Close the table and hold the name lock.
 
     thd                           Thread object
     table                         Table object
@@ -8801,12 +8856,14 @@ bool is_equal(const LEX_STRING *a, const
     old_lock_level                Old lock level
 */
 
-int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
+int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
 {
-  DBUG_ENTER("abort_and_upgrade_lock");
+  DBUG_ENTER("abort_and_upgrade_lock_and_close_table");
 
   if (wait_while_table_is_used(lpt->thd, lpt->table, HA_EXTRA_FORCE_REOPEN))
     DBUG_RETURN(1);
+  if (alter_close_tables(lpt))
+    DBUG_RETURN(1);
   DBUG_RETURN(0);
 }
 

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2010-04-29 20:33:06 +0000
+++ b/sql/sql_partition.cc	2010-05-11 14:15:40 +0000
@@ -6283,54 +6283,6 @@ static void alter_partition_lock_handlin
     sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
 }
 
-/*
-  Unlock and close table before renaming and dropping partitions
-  SYNOPSIS
-    alter_close_tables()
-    lpt                        Struct carrying parameters
-  RETURN VALUES
-    0
-*/
-
-static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
-  TABLE_SHARE *share= lpt->table->s;
-  THD *thd= lpt->thd;
-  TABLE *table;
-  DBUG_ENTER("alter_close_tables");
-  /*
-    We must keep LOCK_open while manipulating with thd->open_tables.
-    Another thread may be working on it.
-  */
-  mysql_mutex_lock(&LOCK_open);
-  /*
-    We can safely remove locks for all tables with the same name:
-    later they will all be closed anyway in
-    alter_partition_lock_handling().
-  */
-  for (table= thd->open_tables; table ; table= table->next)
-  {
-    if (!strcmp(table->s->table_name.str, share->table_name.str) &&
-	!strcmp(table->s->db.str, share->db.str))
-    {
-      mysql_lock_remove(thd, thd->lock, table);
-      table->file->close();
-      table->db_stat= 0;                        // Mark file closed
-      /*
-        Ensure that we won't end up with a crippled table instance
-        in the table cache if an error occurs before we reach
-        alter_partition_lock_handling() and the table is closed
-        by close_thread_tables() instead.
-      */
-      tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
-                       table->s->db.str,
-                       table->s->table_name.str);
-    }
-  }
-  mysql_mutex_unlock(&LOCK_open);
-  DBUG_RETURN(0);
-}
-
 
 /*
   Handle errors for ALTER TABLE for partitioning
@@ -6629,9 +6581,7 @@ uint fast_alter_partition_table(THD *thd
         write_log_drop_partition(lpt) ||
         ERROR_INJECT_CRASH("crash_drop_partition_3") ||
         (not_completed= FALSE) ||
-        abort_and_upgrade_lock(lpt) ||
-        ERROR_INJECT_CRASH("crash_drop_partition_4") ||
-        alter_close_tables(lpt) ||
+        abort_and_upgrade_lock_and_close_table(lpt) ||
         ERROR_INJECT_CRASH("crash_drop_partition_5") ||
         ((!thd->lex->no_write_to_binlog) &&
          (write_bin_log(thd, FALSE,
@@ -6697,9 +6647,7 @@ uint fast_alter_partition_table(THD *thd
         ERROR_INJECT_CRASH("crash_add_partition_2") ||
         mysql_change_partitions(lpt) ||
         ERROR_INJECT_CRASH("crash_add_partition_3") ||
-        abort_and_upgrade_lock(lpt) ||
-        ERROR_INJECT_CRASH("crash_add_partition_4") ||
-        alter_close_tables(lpt) ||
+        abort_and_upgrade_lock_and_close_table(lpt) ||
         ERROR_INJECT_CRASH("crash_add_partition_5") ||
         ((!thd->lex->no_write_to_binlog) &&
          (write_bin_log(thd, FALSE,
@@ -6782,9 +6730,7 @@ uint fast_alter_partition_table(THD *thd
         write_log_final_change_partition(lpt) ||
         ERROR_INJECT_CRASH("crash_change_partition_4") ||
         (not_completed= FALSE) ||
-        abort_and_upgrade_lock(lpt) ||
-        ERROR_INJECT_CRASH("crash_change_partition_5") ||
-        alter_close_tables(lpt) ||
+        abort_and_upgrade_lock_and_close_table(lpt) ||
         ERROR_INJECT_CRASH("crash_change_partition_6") ||
         ((!thd->lex->no_write_to_binlog) &&
          (write_bin_log(thd, FALSE,

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-04-27 09:58:21 +0000
+++ b/sql/sql_show.cc	2010-05-11 14:15:40 +0000
@@ -49,7 +49,8 @@
 #include "event_data_objects.h"
 #endif
 #include <my_dir.h>
-#include "lock.h"                           // MYSQL_LOCK_IGNORE_FLUSH
+#include "debug_sync.h"
+#include "lock.h"                           // MYSQL_OPEN_IGNORE_FLUSH
 
 #define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
 
@@ -3538,6 +3539,7 @@ int get_all_tables(THD *thd, TABLE_LIST 
             lex->sql_command= SQLCOM_SHOW_FIELDS;
             show_table_list->i_s_requested_object=
               schema_table->i_s_requested_object;
+            DEBUG_SYNC(thd, "before_open_in_get_all_tables");
             res= open_normal_and_derived_tables(thd, show_table_list,
                    (MYSQL_OPEN_IGNORE_FLUSH |
                     MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |


Attachment: [text/bzr-bundle] bzr/alexey.kopytov@sun.com-20100511141540-wfrwlq1roe4fvyk9.bundle
Thread
bzr commit into mysql-trunk branch (Alexey.Kopytov:3019) Bug#50561Alexey Kopytov11 May