List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:March 18 2009 10:31am
Subject:bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2832)
Bug#42861
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-42861/mysql-5.1-bugteam/ based on revid:joro@stripped

 2832 Alfranio Correia	2009-03-18
      Bug #42861 Assigning invalid directories to --slave-load-tmpdir crashes the slave
      
      Compiling with debug and assigning an invalid directory to --slave-load-tmpdir
      was crashing the slave due to the following assertion DBUG_ASSERT(! is_set() ||
      can_overwrite_status). This assertion assumes that a thread can change its
      state once (i.e. ok,error, etc) before aborting, cleaning/resuming or completing
      its execution unless the overwrite flag (i.e. can_overwrite_status) is true.
      
      The Append_block_log_event::do_apply_event which is responsible for creating
      temporary file(s) was not cleaning the thread state. Thus a failure while
      trying to create a file in an invalid temporary directory was causing the crash.
      
      To fix the problem we check if the temporary directory is valid before starting
      the SQL Thread and reset the thread state before creating a file in
      Append_block_log_event::do_apply_event.
added:
  mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result
  mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result
  mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile-slave.opt
  mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test
  mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt
  mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test
modified:
  mysql-test/suite/rpl/r/rpl_slave_load_in.result
  mysql-test/suite/rpl/t/rpl_slave_load_in.test
  sql/log_event.cc
  sql/slave.cc

=== modified file 'mysql-test/suite/rpl/r/rpl_slave_load_in.result'
--- a/mysql-test/suite/rpl/r/rpl_slave_load_in.result	2009-02-21 09:36:07 +0000
+++ b/mysql-test/suite/rpl/r/rpl_slave_load_in.result	2009-03-18 10:31:17 +0000
@@ -5,6 +5,15 @@ reset slave;
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
 start slave;
 create table t1(a int not null auto_increment, b int, primary key(a));
+create table t2(a int not null auto_increment, b int, primary key(a)) engine=innodb;
 load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+start transaction;
+insert into t2(b) values (1);
+insert into t2(b) values (2);
+load data infile '../../std_data/rpl_loaddata.dat' into table t2;
+load data infile '../../std_data/rpl_loaddata.dat' into table t2;
+commit;
 Comparing tables master:test.t1 and slave:test.t1
+Comparing tables master:test.t2 and slave:test.t2
 drop table t1;
+drop table t2;

=== added file 'mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result'
--- a/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result	2009-03-18 10:31:17 +0000
@@ -0,0 +1,15 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+create table t1(a int not null auto_increment, b int, primary key(a)) engine=innodb;
+start transaction;
+insert into t1(b) values (1);
+insert into t1(b) values (2);
+load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+commit;
+Error in Begin_load_query event: write to '../../tmp/SQL_LOAD-2-1-1.data' failed
+drop table t1;
+drop table t1;

=== added file 'mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result'
--- a/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result	2009-03-18 10:31:17 +0000
@@ -0,0 +1,2 @@
+start slave;
+Unable to use slave's temporary directory ../../../error - Can't read dir of '../../../error' (Errcode: 2)

=== modified file 'mysql-test/suite/rpl/t/rpl_slave_load_in.test'
--- a/mysql-test/suite/rpl/t/rpl_slave_load_in.test	2009-02-21 09:36:07 +0000
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_in.test	2009-03-18 10:31:17 +0000
@@ -3,10 +3,11 @@
 # event while the "--secure-file-priv" option is set.
 # 
 # The test is divided in two steps:
-#    1 - Creates a table and populates it through "LOAD DATA INFILE".
+#    1 - Creates tables and populates them through "LOAD DATA INFILE".
 #    2 - Compares the master and slave.
 ##########################################################################
-source include/master-slave.inc;
+--source include/have_innodb.inc
+--source include/master-slave.inc
 
 ##########################################################################
 #                            Loading data
@@ -14,8 +15,17 @@ source include/master-slave.inc;
 connection master;
 
 create table t1(a int not null auto_increment, b int, primary key(a));
+create table t2(a int not null auto_increment, b int, primary key(a)) engine=innodb;
+
 load data infile '../../std_data/rpl_loaddata.dat' into table t1;
 
+start transaction;
+  insert into t2(b) values (1);
+  insert into t2(b) values (2);
+  load data infile '../../std_data/rpl_loaddata.dat' into table t2;
+  load data infile '../../std_data/rpl_loaddata.dat' into table t2;
+commit;
+
 ##########################################################################
 #                       Checking Consistency
 ##########################################################################
@@ -25,11 +35,16 @@ let $diff_table_1=master:test.t1;
 let $diff_table_2=slave:test.t1;
 source include/diff_tables.inc;
 
+let $diff_table_1=master:test.t2;
+let $diff_table_2=slave:test.t2;
+source include/diff_tables.inc;
+
 ##########################################################################
 #                             Clean up
 ##########################################################################
 connection master;
 
 drop table t1;
+drop table t2;
 
 sync_slave_with_master;

=== added file 'mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile-slave.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile-slave.opt	2009-03-18 10:31:17 +0000
@@ -0,0 +1 @@
+--loose-debug=d,remove_slave_load_file_before_write

=== added file 'mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test'
--- a/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test	2009-03-18 10:31:17 +0000
@@ -0,0 +1,46 @@
+##########################################################################
+# This test verifies if the slave fails gracefully when the temporary 
+# file used to load data is removed while it is about to be used it. 
+# Similar errors are caught if the temporary directory is removed.
+#
+# Steps:
+#    1 - Creates a table and populates it through "LOAD DATA INFILE".
+#    2 - Catches error.
+##########################################################################
+--source include/have_binlog_format_mixed_or_statement.inc
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/master-slave.inc
+
+##########################################################################
+#                            Loading data
+##########################################################################
+connection master;
+
+create table t1(a int not null auto_increment, b int, primary key(a)) engine=innodb;
+
+start transaction;
+  insert into t1(b) values (1);
+  insert into t1(b) values (2);
+  load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+commit;
+
+##########################################################################
+#                            Catch Error
+##########################################################################
+connection slave;
+source include/wait_for_slave_sql_to_stop.inc;
+
+let $error=query_get_value("show slave status", Last_SQL_Error, 1);
+echo $error;
+
+##########################################################################
+#                             Clean up
+##########################################################################
+connection master;
+
+drop table t1;
+
+connection slave;
+
+drop table t1;

=== added file 'mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt	2009-03-18 10:31:17 +0000
@@ -0,0 +1 @@
+--slave-load-tmpdir=../../../error

=== added file 'mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test'
--- a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test	2009-03-18 10:31:17 +0000
@@ -0,0 +1,15 @@
+##########################################################################
+# This test verifies if the start slave fails gracefuly when an 
+# invalid directory is used to set --slave-load-tmpdir.
+##########################################################################
+connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+connect (slave1,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+
+connection slave;
+start slave;
+
+source include/wait_for_slave_sql_to_stop.inc;
+let $error=query_get_value("show slave status", Last_SQL_Error, 1);
+echo $error;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-03-05 10:23:46 +0000
+++ b/sql/log_event.cc	2009-03-18 10:31:17 +0000
@@ -382,7 +382,7 @@ static void cleanup_load_tmpdir()
   uint i;
   char fname[FN_REFLEN], prefbuf[31], *p;
 
-  if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
+  if (!(dirp=my_dir(slave_load_tmpdir,MYF(0))))
     return;
 
   /* 
@@ -6178,6 +6178,12 @@ int Append_block_log_event::do_apply_eve
   thd_proc_info(thd, proc_info);
   if (get_create_or_append())
   {
+    /*
+      Usually lex_start() is called by mysql_parse(), but we need it here
+      as the present method does not call mysql_parse().
+    */
+    lex_start(thd);
+    mysql_reset_thd_for_next_command(thd);
     my_delete(fname, MYF(0)); // old copy may exist already
     if ((fd= my_create(fname, CREATE_MODE,
 		       O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
@@ -6197,6 +6203,10 @@ int Append_block_log_event::do_apply_eve
                 get_type_str(), fname);
     goto err;
   }
+
+  DBUG_EXECUTE_IF("remove_slave_load_file_before_write", 
+                  my_close(fd,MYF(0)); fd= -1; my_delete(fname, MYF(0)););
+
   if (my_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
   {
     rli->report(ERROR_LEVEL, my_errno,

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-01-09 12:49:24 +0000
+++ b/sql/slave.cc	2009-03-18 10:31:17 +0000
@@ -2632,6 +2632,41 @@ err:
   DBUG_RETURN(0);                               // Can't return anything here
 }
 
+/*
+  Check the temporary directory used by commands like
+  LOAD DATA INFILE.
+ */
+static 
+int check_temp_dir(char* tmp_dir, char *tmp_file)
+{
+  int fd;
+  MY_DIR *dirp;
+
+  DBUG_ENTER("check_temp_dir");
+
+  /*
+    Check if the directory exists.
+   */
+  if (!(dirp=my_dir(tmp_dir,MYF(MY_WME))))
+    DBUG_RETURN(1);
+  my_dirend(dirp);
+
+  /*
+    Check permissions to create a file.
+   */
+  if ((fd= my_create(tmp_file, CREATE_MODE,
+                     O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+                     MYF(MY_WME))) < 0)
+  DBUG_RETURN(1);
+
+  /*
+    Clean up.
+   */
+  my_close(fd, MYF(0));
+  my_delete(tmp_file, MYF(0));
+
+  DBUG_RETURN(0);
+}
 
 /**
   Slave SQL thread entry point.
@@ -2763,6 +2798,14 @@ log '%s' at position %s, relay log '%s' 
                     llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
                     llstr(rli->group_relay_log_pos,llbuff1));
 
+  if (check_temp_dir(slave_load_tmpdir, rli->slave_patternload_file))
+  {
+    rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), 
+                "Unable to use slave's temporary directory %s - %s", 
+                slave_load_tmpdir, thd->main_da.message());
+    goto err;
+  }
+
   /* execute init_slave variable */
   if (sys_init_slave.value_length)
   {

Thread
bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2832)Bug#42861Alfranio Correia18 Mar
  • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2832)Bug#42861He Zhenxing19 Mar