MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Satya B Date:April 16 2009 11:32am
Subject:bzr commit into mysql-5.1-bugteam branch (satya.bn:2863) Bug#40827
View as plain text  
#At file:///home/satya/WORK/mysql-5.1-bugteam-40827-push/ based on revid:staale.smedseng@stripped

 2863 Satya B	2009-04-16
      BUG#40827 - Killing insert-select to MyISAM can cause table corruption
                        
      Killing insert-select statement on MyISAM corrupts the table.
                        
      Killing the insert-select statement corrupts the MyISAM table only
      when the destination table is empty and when it has indexes. When 
      we bulk insert huge data and if the destination table is empty we 
      disable the indexes for fast inserts, data is then inserted and 
      indexes are re-enabled after bulk_insert operation
                        
      Killing the query, aborts the repair table operation during enable
      indexes phase leading to table corruption.
                      
      We now truncate the table when we detect that enable indexes is
      killed for bulk insert query.As we have an empty table before the 
      operation, we can fix by truncating the table.
      modified:
        mysql-test/r/myisam.result
        mysql-test/t/myisam.test
        storage/myisam/ha_myisam.cc

per-file messages:
  mysql-test/r/myisam.result
    Result file for BUG#40827
  mysql-test/t/myisam.test
    Testcase for BUG#40827
  storage/myisam/ha_myisam.cc
    Fixed end_bulk_insert() method to truncate the table when we detect enable 
    index operation is killed.
=== modified file 'mysql-test/r/myisam.result'
--- a/mysql-test/r/myisam.result	2008-09-06 00:51:17 +0000
+++ b/mysql-test/r/myisam.result	2009-04-16 11:32:56 +0000
@@ -2226,4 +2226,43 @@ Key Start Len Index   Type
 1   2     30  multip. varchar              
 2   33    30  multip. char NULL            
 DROP TABLE t1;
+#
+# BUG#40827 - Killing insert-select to MyISAM can cause table corruption
+#
+CREATE TABLE `t1` (
+`id` BIGINT(20) ,
+`id1` BIGINT(20) AUTO_INCREMENT,
+KEY(id1), KEY(id)
+) ENGINE=MyISAM;
+CREATE TABLE `t2` (
+`id` BIGINT(20) ,
+`id1` BIGINT(20) AUTO_INCREMENT,
+KEY (id1), KEY(id)
+) ENGINE=MyISAM;
+INSERT INTO t2 (id) VALUES (123);
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+INSERT INTO t2 (id) SELECT id  FROM t2;
+# Switch to insert Connection
+SET SESSION debug='+d,wait_in_enable_indexes';
+# Send insert data
+INSERT INTO t1(id) SELECT id  FROM t2;
+# Switch to default Connection
+# Wait for insert data to reach the debug point
+SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE STATE = 'wait_in_enable_indexes' AND 
+INFO = "INSERT INTO t1(id) SELECT id  FROM t2" 
+INTO @thread_id;
+KILL QUERY @thread_id;
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+DROP TABLE t1,t2;
 End of 5.1 tests

=== modified file 'mysql-test/t/myisam.test'
--- a/mysql-test/t/myisam.test	2008-09-06 00:51:17 +0000
+++ b/mysql-test/t/myisam.test	2009-04-16 11:32:56 +0000
@@ -1478,5 +1478,57 @@ let $MYSQLD_DATADIR= `select @@datadir`;
 --exec $MYISAMCHK -d $MYSQLD_DATADIR/test/t1
 DROP TABLE t1;
 
+--echo #
+--echo # BUG#40827 - Killing insert-select to MyISAM can cause table corruption
+--echo #
+
+CONNECT (insertConn, localhost, root,,);
+
+CREATE TABLE `t1` (
+`id` BIGINT(20) ,
+`id1` BIGINT(20) AUTO_INCREMENT,
+ KEY(id1), KEY(id)
+) ENGINE=MyISAM;
+
+CREATE TABLE `t2` (
+`id` BIGINT(20) ,
+`id1` BIGINT(20) AUTO_INCREMENT,
+ KEY (id1), KEY(id)
+) ENGINE=MyISAM;
+
+INSERT INTO t2 (id) VALUES (123);
+
+let $i = 10; 
+while ($i)
+{
+  INSERT INTO t2 (id) SELECT id  FROM t2; 
+  dec $i; 
+}
+
+--echo # Switch to insert Connection
+CONNECTION insertConn;
+SET SESSION debug='+d,wait_in_enable_indexes';
+--echo # Send insert data
+SEND INSERT INTO t1(id) SELECT id  FROM t2; 
+
+--echo # Switch to default Connection
+CONNECTION default;
+--echo # Wait for insert data to reach the debug point
+
+let $wait_condition=
+  SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
+  WHERE STATE = "wait_in_enable_indexes" AND 
+  INFO = "INSERT INTO t1(id) SELECT id  FROM t2";
+--source include/wait_condition.inc
+
+SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE STATE = 'wait_in_enable_indexes' AND 
+INFO = "INSERT INTO t1(id) SELECT id  FROM t2" 
+INTO @thread_id;
+
+KILL QUERY @thread_id;
+CHECK TABLE t1; 
+DROP TABLE t1,t2;
+DISCONNECT insertConn;
 --echo End of 5.1 tests
 

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2009-04-08 06:55:19 +0000
+++ b/storage/myisam/ha_myisam.cc	2009-04-16 11:32:56 +0000
@@ -43,6 +43,28 @@ TYPELIB myisam_stats_method_typelib= {
   array_elements(myisam_stats_method_names) - 1, "",
   myisam_stats_method_names, NULL};
 
+#ifndef DBUG_OFF
+/**
+  Causes the thread to wait in a spin lock for a query kill signal.
+  This function is used by the test frame work to identify race conditions.
+
+  The signal is caught and ignored and the thread is not killed.
+*/
+
+static void debug_wait_for_kill(const char *info)
+{
+  DBUG_ENTER("debug_wait_for_kill");
+  const char *prev_info;
+  THD *thd;
+  thd= current_thd;
+  prev_info= thd_proc_info(thd, info);
+  while(!thd->killed)
+    my_sleep(1000);
+  DBUG_PRINT("info", ("Exit debug_wait_for_kill"));
+  thd_proc_info(thd, prev_info);
+  DBUG_VOID_RETURN;
+}
+#endif
 
 /*****************************************************************************
 ** MyISAM tables
@@ -1395,6 +1417,9 @@ int ha_myisam::enable_indexes(uint mode)
 {
   int error;
 
+  DBUG_EXECUTE_IF("wait_in_enable_indexes",
+                  debug_wait_for_kill("wait_in_enable_indexes"); );
+
   if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
   {
     /* All indexes are enabled already. */
@@ -1508,8 +1533,9 @@ void ha_myisam::start_bulk_insert(ha_row
     /*
       Only disable old index if the table was empty and we are inserting
       a lot of rows.
-      We should not do this for only a few rows as this is slower and
-      we don't want to update the key statistics based of only a few rows.
+      Note that in end_bulk_insert() we may truncate the table if
+      enable_indexes() failed, thus it's essential that indexes are
+      disabled ONLY for an empty table.
     */
     if (file->state->records == 0 && can_enable_indexes &&
         (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
@@ -1541,8 +1567,27 @@ int ha_myisam::end_bulk_insert()
 {
   mi_end_bulk_insert(file);
   int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
-  return err ? err : can_enable_indexes ?
-                     enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
+  if (!err)
+  {
+    if (can_enable_indexes)
+    {
+      /* 
+        Truncate the table when enable index operation is killed. 
+        After truncating the table we don't need to enable the 
+        indexes, because the last repair operation is aborted after 
+        setting the indexes as active and  trying to recreate them. 
+     */
+   
+      if (((err= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE)) != 0) && 
+                                                  current_thd->killed)
+      {
+        delete_all_rows();
+        /* not crashed, despite being killed during repair */
+        file->s->state.changed&= ~(STATE_CRASHED|STATE_CRASHED_ON_REPAIR);
+      }
+    } 
+  }
+  return err;
 }
 
 

Thread
bzr commit into mysql-5.1-bugteam branch (satya.bn:2863) Bug#40827Satya B16 Apr
  • Re: bzr commit into mysql-5.1-bugteam branch (satya.bn:2863)Bug#40827Sergei Golubchik29 Apr